1、贪心算法一、算法思想贪心法的基本思路:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。该算法存在问题:1. 不能保证求得的最后解是最佳的;2. 不能用来求最大或最小解问题;3. 只能求满足某些约束条件的可行解的范围。实现该算法的过程:从问题的某一初始解出发;while 能朝给定总目标前进一步 do求出可行解的一个解元素;由所有解元素组合成问题的一个可行解;二、例题分析1、 背包问题 有一个背包,背包容量是 M=150。有 7 个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。物品
2、A B C D E F G重量 wi 35 30 60 50 40 10 25价值 pi 10 40 30 50 35 40 30分析:目标函数: pi 最大约束条件是装入的物品总重量不超过背包容量:wi=fj thenbegin a ai;j:=i;endend;例 1 找零钱 一个小孩买了价值少于 1 美元的糖,并将 1 美元的钱交给售货员。售货员希望用数目最少的硬币找给小孩。假设提供了数目不限的面值为 2 5 美分、1 0 美分、5 美分、及 1 美分的硬币。售货员分步骤组成要找的零钱数,每次加入一个硬币。选择硬币时所采用的贪婪准则如下:每一次选择应使零钱数尽量增大。为保证解法的可行性(
3、即:所给的零钱等于要找的零钱数),所选择的硬币不应使零钱总数超过最终所需的数目。 假设需要找给小孩 6 7 美分,首先入选的是两枚 2 5 美分的硬币,第三枚入选的不能是2 5 美分的硬币,否则硬币的选择将不可行(零钱总数超过 6 7 美分),第三枚应选择 1 0美分的硬币,然后是 5 美分的,最后加入两个 1 美分的硬币。 贪婪算法有种直觉的倾向,在找零钱时,直觉告诉我们应使找出的硬币数目最少(至少是接近最少的数目)。可以证明采用上述贪婪算法找零钱时所用的硬币数目的确最少(见练习 1)。 例 2 机器调度 现有 n 件任务和无限多台的机器,任务可以在机器上得到处理。每件任务的开始时间为 si
4、,完成时间为 fi ,si k。寻找 1 ,n范围内最小的整数 j,使得 xjyj 。若没有这样的 j 存在,则 n i= 1xi =n i = 1yi 。如果有这样的 j 存在,则 jk,否则 y 就不是一个可行解,因为 xjyj ,xj = 1 且 yj = 0。令 yj = 1,若结果得到的 y 不是可行解,则在 j+ 1 ,n范围内必有一个 l 使得yl = 1。令 yl = 0,由于 wjwl ,则得到的 y 是可行的。而且,得到的新 y 至少与原来的y 具有相同数目的 1。 经过数次这种转化,可将 y 转化为 x。由于每次转化产生的新 y 至少与前一个 y 具有相同数目的 1,因此
5、 x 至少与初始的 y 具有相同的数目 1。货箱装载算法的 C + +代码实现见程序 1 3 - 1。由于贪婪算法按货箱重量递增的顺序装载,程序 1 3 - 1 首先利用间接寻址排序函数 I n d i r e c t S o r t 对货箱重量进行排序(见 3 . 5 节间接寻址的定义) ,随后货箱便可按重量递增的顺序装载。由于间接寻址排序所需的时间为 O (nl o gn)。 程序 13-1 货箱装船 template void ContainerLoading(int x, T w, T c, int n) / 货箱装船问题的贪婪算法 / xi = 1 当且仅当货箱 i 被装载, 10
6、时总的时间开销为 O (nk+1 )。实际观察到的性能要好得多。-找零钱问题的贪心算法问题描述: 当前有面值分别为 2 角 5 分,1 角,5 分,1 分的硬币,请给出找 n 分钱的最佳方案(要求找出的硬币数目最少) 问题分析: 根据常识,我们到店里买东西找钱时,老板总是先给我们最大面值的,要是不够再找面值小一点的,直到找满为止。如果老板都给你找分数的或者几角的,那你肯定不干,另外,他也可能没有那么多零碎的钱给你找。其实这就是一个典型的贪心选择问题。 问题的算法设计与实现: 先举个例子,假如老板要找给我 99 分钱,他有上面的面值分别为 25,10,5,1 的硬币数,为了找给我最少的硬币数,那
7、么他是不是该这样找呢,先看看该找多少个 25 分的, 99253,好像是 3 个,要是 4 个的话,我们还得再给老板一个 1 分的,我不干,那么老板只能给我 3 个 25 分,由于还少给我 24,所以还得给我 2 个 10 分的和 4 个 1 分。 具体实现 /找零钱算法 /By falcon /输入:数组 m,依次存放从大到小排列的面值数,n 为需要找的钱数,单位全部为分 /输出:数组 num,对照数组 m 中的面值存放不同面值的硬币的个数,即找钱方案比如要找 N 分钱,先拿 N 除最大零钱面值,可以取模得出余数。 当然取整就是所找的最大面值零钱的个数。 所得余数再次处理,用的是一个循环结构
8、。 N 输入取值 M 是定义的面值 M0是最大面值 K 是一个数组,存储各面值零钱的个数 i=0 do while (N0) K0=int(N/Mi) N=mod(N,Mi) i+ end do-贪心算法背包问题解题报告问题描述:假定有 n 个物体和一个背包,物体 i 有质量 wi,价值为 pi,而背包的载荷能力为 M。若将物体 i 的一部分 xi(10,1struct goodinfofloat p; /物品效益float w; /物品重量float X; /物品该放的数量int flag; /物品编号; /物品信息结构体void Insertionsort(goodinfo goods,i
9、nt n)int j,i;for(j=2;jgoodsi.p)goodsi+1=goodsi;i-;goodsi+1=goods0; /按物品效益,重量比值做升序排列void bag(goodinfo goods,float M,int n) float cu;int i,j;for(i=1;icu)/当该物品重量大与剩余容量跳出break;goodsi.X=1;cu=cu-goodsi.w;/确定背包新的剩余容量if(in;goods=new struct goodinfo n+1;/coutM;coutgoodsi.w;coutgoodsi.p;goodsi.p=goodsi.p/goodsi.w;/得出物品的效益,重量比cout to run agian“ to exit“j;