贪心算法经典例题
在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,
通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。
从贪心算法的定义可以看出,贪心法并不是从整体上考虑问题,它所做出的选择只是在某种意义上
的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。
我们看看下面的例子
例 1 均分纸牌(NOIP2002tg)
[问题描述] 有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。
可以在任一堆上取若干张纸牌,然后移动。移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2
的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻
左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如
N=4,4 堆纸牌数分别为:
① 9 ② 8 ③ 17 ④ 6
移动 3 次可达到目的:
从 ③ 取 4 张牌放到 ④ (9 8 13 10) -> 从 ③ 取 3 张牌放到 ②(9 11 10 10)-> 从 ② 取
1 张牌放到①(10 10 10 10)。
[输 入]:键盘输入文件名。
文件格式:N(N 堆纸牌,1 <= N <= 100)
A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
[输 出]:输出至屏幕。格式为:所有堆均达到相等时的最少移动次数。
[输入输出样例]
a.in:
4
9 8 17 6
屏慕显示:3
算法分析:设 a[i]为第 i 堆纸牌的张数(0<=i<=n),v 为均分后每堆纸牌的张数,s 为最小移到
次数。
我们用贪心法,按照从左到右的顺序移动纸牌。如第 i 堆(0<i<n)的纸牌数 a[i]不等于平均值,则移
动一次(即 s 加 1),分两种情况移动:
(1) 若 a[i]>v,则将 a[i]-v 张纸牌从第 I 堆移动到第 I+1 堆;
(2) 若 a[i]<v,则将 v -a[i]张纸牌从第 I+1 堆移动到第 I 堆;
为了设计的方便,我们把这两种情况统一看作是将 a[I]-v 张牌从第 I 堆移动到第 I+1 堆;移动后有:
a[I]:=v;a[I+1]:=a[I+1]+a[I]-v;
在从第 i+1 堆中取出纸牌补充第 i 堆的过程中,可能会出现第 i+1 堆的纸牌数小于零(a[i+1]+a[i]-
v<0 )的情况。
如 n=3,三堆纸牌数为(1,2,27)这时 v=10,为了使第一堆数为 10,要从第二堆移 9 张纸牌
到第一堆,而第二堆只有 2 张纸牌可移,这是不是意味着刚才使用的贪心法是错误的呢?
我们继续按规则分析移牌过程,从第二堆移出 9 张到第一堆后,第一堆有 10 张纸牌,第二堆剩下-7
张纸牌,再从第三堆移动 17 张到第二堆,刚好三堆纸牌数都是 10,最后结果是对的,从第二堆移出的牌
都可以从第三堆得到。我们在移动过程中,只是改变了移动的顺序,而移动的次数不变,因此此题使用贪
心法是可行的。
评论1