算法 - 贪心算法

简介:

贪心算法是使所做的选择看起来都是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解。

思想:

把问题分解为多个子问题,只要依次求出子问题的最优解,就能得到最终问题的最优解。即,只需要考虑局部最优,就能得到全局最优。

简单的应用1:剪绳子

问题描述

给你一个长度为n的绳子,请把绳子剪成m段(m,n都是整数,且都大于1)每段绳子的长度即为K[0],K[1],K[2]...K[m]。请问K[0]*k[1]...*k[m]可能的最大乘积是多少?

解决思路

如果我们按照如下的策略剪绳子,则得到的各段绳子的长度的乘积将最大;当n>=5,我们尽可能地剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪为长度为2的绳子.

贪心算法的核心是通过局部最优解来得到全局最优解,对于分割问题来说,要使乘积最大,该问题的贪心思想是尽可能去剪为长度为3的绳子!

Java代码实现

迭代法

java 复制代码
public static int greedy_cut_rope_1(int n) {
   if(n<2)
       return 0;
   if(n==2)
       return 1;
   if(n==3)
       return 2;
   //尽可能多地去减长度为3的绳子段
   int timesOf3 = n/3;
   //当绳子最后剩下的长度为4的时候,不能再去剪去长度为3的绳子段
   if(n-timesOf3*3==1)
       timesOf3-=1;
   int timesOf2 =(n-timesOf3*3)/2;
   return (int) (Math.pow(3,timesOf3)*Math.pow(2,timesOf2));
}

递归法

java 复制代码
public static int greedy_cut_rope(int n) {
   if(n==2)
       return 2;
   if(n==3)
       return 3;
   if(n<2)
       return 1;
   //int timesOf3 = n/3;
   if(n==4)
       return 4;
   return 3*greedy_cut_rope(n-3);
}

简单的应用2:背包问题

问题描述

给定N个物品和一个容量为C的背包,物品i的重量为Wi,其价值为Vi,背包问题是如何选择装入背包的物品,使得装入背包中物品的总价值最大。注意在背包问题中,可以将某种物品的一部分装入背包中,但是不可以重复装入。

解决思路

三种贪心思想:

选择价值最大的物品

选择重量最轻的物品

选择单位重量价值最大的物品

毫无疑问,我们当然选择第三种咯。先把性价比最高的全部装入,最后不足全部装入的部分装入。

Java代码实现

java 复制代码
public static int greedy_knapSack(int[] w,int[] v,int n,int c) {
   //  假设物品已按单位重量降序排列
   double[] x = new double[10];
   int maxValue =0;
   int i;
   for(i=0;w[i]<c;i++) {
       x[i]=1; //将物品 i 装入背包
       maxValue+=v[i];
       c=c-w[i]; // 背包剩余数量
   }
   x[i]=(double)c/w[i];    //物品i装入一部分
   maxValue+=x[i]*v[i];
   return maxValue;    //返回背包获得的价值
}

简单的应用3:活动选择问题

问题描述

假设有一个需要使某一资源的n个活动组成的集合S={a1,a2,a3...an}。该资源一次只能被一个活动占用,每个活动ai有一个开始时间Si和结束时间Fi,且0<=Si<Fi<∞。一旦被选择后,活动ai就占据半开时间区间[Si,Fi)。如果区间[Si,Fi)与 [Sj,Fj)互不重叠,称活动ai与aj是兼容的。活动选择问题就是要选择出一个由互相兼容的问题组成的最大集合。

讨论下面的活动集合S,其中各活动已按结束时间的单调递增顺序进行了排序:

解决思路

对于任意非空子问题Sij,设am是Sij中具有最早结束时间的活动:

fm=min{fk:ak∈Sij}

那么:

1.活动am在Sij的某最大兼容活动子集中被使用。

2.子问题Sim为空,所以选择am使子问题Smj为唯一可能非空的子问题。

在解决子问题时,选择am是一个可被合法调度、具有最早结束时间的活动。从直觉上来看,这种活动选择方法是一种贪婪技术,他给后面剩下的待调度任务留下了尽可能多的机会。也就是说,此处的贪心选择使得剩下的、未调度的时间最大化。

Java代码实现

java 复制代码
public static void greedy_activity_selector(int[] s,int[] f,boolean[] b) {
   int n = s.length-1;
   b[1]=true;
   int j=1;
   for(int i =2;i<=n;i++) {
       if(s[i]>f[j]) {
           b[i]=true;
           j=i;
       }else
           b[i]=false;
   }
   for(int i=1;i<b.length;i++)
       System.out.println(b[i]);
}
相关推荐
沐怡旸3 小时前
【算法】【链表】328.奇偶链表--通俗讲解
算法·面试
掘金安东尼6 小时前
Amazon Lambda + API Gateway 实战,无服务器架构入门
算法·架构
码流之上7 小时前
【一看就会一写就废 指间算法】设计电子表格 —— 哈希表、字符串处理
javascript·算法
快手技术9 小时前
快手提出端到端生成式搜索框架 OneSearch,让搜索“一步到位”!
算法
CoovallyAIHub1 天前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP1 天前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo1 天前
半开区间和开区间的两个二分模版
算法
moonlifesudo1 天前
300:最长递增子序列
算法
CoovallyAIHub1 天前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉