终于等到你!
什么是贪心算法?
贪心算法其实就是一种解决问题的策略,用这个策略解决问题的时候,
该算法会先把解决问题的过程分成若干步,然后依次解决每一步时都选择当前看起来最优的解法,最后企图以此得到最终问题的最优解。
解决每一步时看似选择了当时最优解,但这种鼠目寸光的局部解决问题的行为并没有考虑整个问题,但又想以局部最优得到全局最优,这正是贪心算法贪心(既要又要)的由来。
三个场景理解贪心算法
场景一:找零问题
假如你买了4块钱的东西,你付给老板50元,老板应找给你46元,此时老板只有若干张20元纸币,10元纸币,5元纸币和1元纸币。要求老板以最少的张数找给你46元。
问你:如何用贪心策略解决此问题呢?
解:首先我们回顾一下贪心算法解决问题步骤:
- 把解决问题的过程分成若干步
- 依次解决每一步时都选择当前看起来最优的解法
- 企图得到最终问题的最优解。
老板找钱的过程肯定是一张钱一张钱的找给你,这也是贪心策略的第一步。以最少的张数找给你46元,那就是找每一张时都选择当时范围内钱数最大的那一张,这是贪心算法的第二步。最后希望得到该问题的最优解。
- 第一步即:找第一张纸币时,要找的钱数46,此时有20,10,5,1,此时这一张纸币的最优选择就是20;
- 第二步即:找第二张纸币时,要找的钱数26,此时有20,10,5,1,此时这一张纸币的最优选择就是20;
- 第三步即:找第三张纸币时,要找的钱数6,此时有20,10,5,1,此时这一张纸币的最优选择就是5;
- 第四步即:找第四张纸币时,要找的钱数1,此时有20,10,5,1,此时这一张纸币的最优选择就是;
用上面这种贪心策略最终得到了该问题的最优解。(证明在文末)
思考一下如果老板以最少的张数找给你46元,但此时只有若干张20元纸币,18元纸币,10元纸币,5元纸币,1元纸币,利用上面这种贪心策略还能得到该问题的最优解吗?
场景二:最小路径和
假如你在A位置,你要走到B位置,规定你每次只能向右或向下走一步,每个格子里是这一步的困难指数。要求选一条路,从A走到B,这条路径的困难指数和是所有从A到B的路径中困难指数和最小的。
问你:如何用贪心策略解决此问题呢?
解:从A开始走,每走一步加一次困难指数,走每一步时都选择当下困难指数最小的一步,最后走到B位置时,希望走的是所有路径中最小困难指数和最小的那条路。
- 走第一步:从A位置出发,此时这一步的最优解法是向下走一步,此时困难指数=1+1=2。
- 走第二步:此时这一步的最优解法是向下走一步,此时困难指数=2+6=8。
- 走第三步:此时这一步的最优解法是向右走一步,此时困难指数=8+1=9。
- 走第四步:此时这一步的最优解法是向右走一步,此时困难指数=9+1=10。
可以看出, 用上面这种贪心策略并没有得到该问题的最优解。因为最优解的最小困难指数应该是1+3+1+1+1 = 7。
场景三:完全背包问题
假如给你一个背包,背包容积V=8,有若干个1 , 2 , 3号物品,他们的体积分别为5,4,1,他们的价值分别为10,7,1。要求往背包里装物品,不超过背包容积的情况下,包里物品的最大价值是多少?
问你:如何用贪心策略解决此问题呢?
解1:以体积为标准,一个一个往背包里装物品,在能装下的情况下每次都装体积最小的物品,最后装到不能再向背包里放物品的时候,希望得到符合题目要求的最优装法。
- 第一步:装第一个物品,此时的最优选择是装3号物品。背包体积剩余7,此时包里物品价值1。
- 第二步:装第二个物品,此时的最优选择是装3号物品。背包体积剩余6,此时包里物品价值2。
- 第三步:装第三个物品,此时的最优选择是装3号物品。背包体积剩余5,此时包里物品价值3。
- 第四步......
- 第五步......
- 第六步.......
- 第七步......
- 第八步:装第八个物品,此时的最优选择是装3号物品。背包体积剩余0,此时包里物品价值8。
可以看出, 用上面这种贪心策略并没有得到该问题的最优解。因为最优解应该是往包里装2个2号物品,此时包里物品价值是14。
解2:以价值为标准,一个一个往背包里装物品,在能装下的情况下每次都装价值最大的物品,最后装到不能再向背包里放物品的时候,希望得到符合题目要求的最优装法。
- 第一步:装第一个物品,此时的最优选择是装一号物品。背包体积剩余3,此时包里物品价值10。
- 第二步:装第二个物品,此时的最优选择是装三号物品。背包体积剩余2,此时包里物品价值11。
- 第三步:装第三个物品,此时的最优选择是装三号物品。背包体积剩余1,此时包里物品价值12。
- 第二步:装第二个物品,此时的最优选择是装三号物品。背包体积剩余0,此时包里物品价值13。
可以看出, 用上面这种贪心策略也没有得到该问题的最优解。因为最优解应该是往包里装2个2号物品,此时包里物品价值是14。
贪心算法的特点:
从上面三个场景中我们很容易能发现:
- 用贪心策略解决问题的时候,每一道题的贪法都是不一样的。因此,贪心算法的提出是没有标准也没有模板的。
- 用贪心策略解决问题的时候,得出的“题解”可能是一个错误的方法。面对错误的贪心策略,我们只需要找到优于贪心策略的解法,就可以证明该贪心策略是错的了。但面对正确的贪心策略,我们需要用数学证明方法证明该贪心策略是对的,才能说该贪心策略是正确的。
最后:小白怎样学习贪心
其实,贪心算法解决问题的步骤就这三步骤:
- 把解决问题的过程分成若干步
- 依次解决每一步时都选择当前看起来最优的解法
- 企图得到最终问题的最优解。
通过上面的例子也很容易理解贪心是什么。
但贪心的难点就在于在面对具体问题时,针对具体不同的各个问题具体怎么贪?如果贪对了,又如何去证明?
所以在面对我们不会的贪心题的时候,放平心态,少问为什么!对,就是少问为什么,为什么这样贪?怎么想到的?大家听过田忌赛马的故事吗?少问为什么就是因为不是人人都是孙膑。把遇到的贪心题都当做经验积累下来就好了。
至于证明正确的贪心策略,兴趣为主!
附:找零问题中贪心策略的证明:
假设在最优解中,20元纸币,10元纸币,5元纸币,1元纸币的张数分别是A,B,C,D。
既然是最优解,我们可以得到以下性质:B<=1,C<=1,D<=4。
这是因为当B=2,即10元纸币有两张时,相当于一张20元纸币,既然是最优解的话,那B肯定不等于2。所以B<=1。C<=1,D<=4同理可证。
假设贪心解中,20元纸币,10元纸币,5元纸币,1元纸币的张数分别是a,b,c,d。
此时我们只要能证明A=a,B=b,C=c,D=d,那就说明贪心解是最优解,即该贪心策略是正确的。
- 证明A=a
贪心解中20元的张数肯定是要贪最多的,可以推出a>=A。
此时只要证明a>A不成立,即可证明a=A。
证明a>A不成立:假设A比a小,已知a=2,所以A=1,此时总的钱数46不变,
在最优解的性质下(B<=1,C<=1,D<=4),只能凑出19元,(19+20)<46,所以a不可能大于A。
即:得证:a=A。
- 证明B=b
已知 a=A,此时B,C,D凑的钱和b,c,d凑的钱相等,同理,贪心解中10元的张数肯定是要贪最多的,所以b代表的张数肯定大于等于B的,即可以推出b>=B,同证明a>A不成立理由一样,b>B不成立。
即:得证B=b。
同理证明C=c,D=d。
本篇完结,下篇总结:用贪心策略解决柠檬水找零问题和将数组和减半的最少操作次数问题,并在文末附证明方法:交换论证法。