算法描述
(1)贪心算法的基本要素
· 贪心选择性质:所谓贪心选择性质是指问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来得到。这是贪心选择可行的第一个要素,也是贪心算法和动态规划的主要区别。动态规划通常以自底向上的方式解各子问题,而贪心算法 通常以自顶向下的方式进行,以迭代的方式相继做出贪心选择,每一次贪心选择就将问题简化为规模更小的子问题。但同时对于每一个子问题,要确定它是否具贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
· 最优子结构性质:问题是否具有最优子结构性质是问题可用动态规划法或者贪心算法求解的关键特征。
· 贪心算法和动态规划法的差异:共同点是都要求问题有最优子结构性质。对于它们的差异,我们拿一个例子说明:
0-1背包问题,不能用贪心算法求解,因为不能得到最优解,因为在这种情况下,它无法保证将背包装满,部分闲置空间使得每公斤背包空间的价值降低了。但对于背包问题,是可以用贪心算法得到最优解的,因为它允许将物品拆开放。事实上,在考虑0-1背包问题时,应该比较选择该物品和不选择该物品所导致的最终方案,然后再做出最好选择。由此就导出许多互相重叠的子问题。这正是问题可用动态规划法求解的另一重要特征。事实上也正是如此,动态规划法的确可以有效的解决0-1背包问题。
差异:动态规划一步一个选择,当前问题依赖于子问题的解,贪心一步一个选择,但不依赖于子问题的解;
动态规划的条件是子问题的重叠性质,所以记录下来以后会用到;贪心是最优子结构性质加贪心性质,即整体最优解可以通过一系列局部最优得到;
动态规划自底向上,贪心自底向下。
(2)对于贪心算法的简述
· 贪心算法应该是集中算法里面最简单的吧。因为没有什么特殊的结构,它非常符合人们日常思维。比如说我们去商场给你一个书包让你随便拿,你先拿什么?肯定是先拿钻石啊,体积质量最小还最贵,接下来应该是珍珠啊古玉啊金子啊之类的,因为这些也都很贵而且不大,这里就体现出单位质量体积价值的概念了。换句话就是说相同大小的东西,我们肯定要值钱的那个,这就是所谓的贪心算法,就是拿单位质量和体积最大价值的东西。
· 顺便说一下,贪心算法要解决需要满足贪心性质和最优子结构性质
例题
例一:活动安排问题
活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子。该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用 公共资源。
设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si <fi 。如果选择了活动i,则它在半开时 间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。
分析:由于输入的活动以其完成时间的非减序排列,所以算法greedySelector每次总是选择具有最早完成时间的相容活动加入集合A中。直观上,按这种方法选择相容活动为未安排活动留下尽可能多的时间。也就是说,该算法的贪心选择的意义是使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。贪心算法并不总能求得问题的最优解,但对于活动安排问题却总能求得问题的整体最优解,即它最终所确定的相容活动集合A的规模最大。这个结论可以用数学归纳法证明。
解答:
int greedySelector(int s[], int f[], int a[])
{
int n=s.length-1;
a[1]=1;//第一个活动肯定是要的,因为它结束时间最早
int j=1;
int count=1;
for(int i=2;i<=n;i++)
{
if(s[i]>=f[j]) //如果下一个的开始时间晚于前一个结束时间
{
a[i]=1;
j=i;
count++;
}
else
a[i]=0;
}
return count;
}
例二:最优装载
问题描述:有一批集装箱要装上一艘载重量为c的轮船,其中集装箱 i 的质量为Wi,体积不受限制的情况下,尽可能多的集装箱装上轮船。
分析:尽可能多的,直接排序,从质量从轻到重的顺序逐个装,这样下来肯定是装的最多的。
做法:排序,装即可,不必赘述。
例三:背包问题和0-1背包问题
问题描述:0-1背包,给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n。
问题分析:这2类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。
贪心法解背包问题:首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。依此策略一直地进行下去,直到背包装满为止。
对于0-1背包问题,贪心选择之所以不能得到最优解是因为在这种情况下,它无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。事实上,在考虑0-1背包问题时,应比较选择该物品和不选择该物品所导致的最终方案,然后再作出最好选择。由此就导出许多互相重叠的子问题。这正是该问题可用动态规划算法求解的另一重要特征。实际上也是如此,动态规划算法的确可以有效地解0-1背包问题。
例四:最小生成树——普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法
例五:最短路径——迪杰斯特拉(Dijkstra)算法
例六:多机调度问题