贪心算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法——活动安排问题 1.对数组f[n]按非减序排序,同时相应地调整s[n]; 2.B={1}; //最优解中包含活动1 3.j=1; i=2; //从活动i开始寻找与活动j相容的活动 4.当(i≤n)时循环执行下列操作 4.1 如果(s[i]>=f[j]) 则 4.1.1 B=B+{j}; 4.1.2 j=i; 4.2 i++;
这是对第一个回合的分析,显然对以后整个取数过程都适 用。也就是说,我们能够控制让计算机自始自终只取一种编号 的数。这样,我们只要比较奇编号数之和与偶编号数之和谁大, 以决定最开始我们是取奇编号数还是偶编号数即可。(如果奇 编号数之和与偶编号数之和同样大,我们第一次可以任意取数,
因为当两者所取数和相同时,先取者为胜。
贪心算法
1 贪心算法基本思想
2 典型贪心算法
3 哈夫曼树
4 最小生成树
贪心算法
1贪心算法的基本思想
贪心法在解决问题的策略上目光短浅,只根据当前已有的信 息就做出选择,而且一旦做出了选择,不管将来有什么结果,这 个选择都不会改变。从问题的某一个初始解出发逐步逼近给定的 目标,每一步都作一个不可回溯的决策,尽可能地求得最好的解。 当达到某算法中的某一步不需要再继续前进时,算法停止。
1 1
4 4
8 8 9 8 8
6 7 8 9 10 11
活动8与活动4相容 活动9、活动10 与活动1不相容 活动11与活动8相容
10
1 1
0 1 2 3 4
4 4
5
11 11
12 13 14
设有n个活动等待安排,这些活动的开始时间和结束时间 分别存放在数组s[n]和f[n]中,集合B存放问题的解,即选定 的活动集合,算法如下:
∞ b 4 0 a 8 h ∞ 4 b 4 0 a 8 h 8 11 7 11 7
8 ∞ i 6 1 2
∞ c
7
∞ d 14 9 e ∞ 10
4 g ∞
2
f ∞
(a)
8 ∞ i 6 1 g ∞ 2 4 f ∞ ∞ c 7 ∞ d 14 9 e ∞ 10 2
其实,若我们只能看到两边的数据,则此题无论先取还 是后取都无必胜的策略。这时一般的策略是用近似贪婪算法。 但若取数者能看到全部2n个数,则此问题可有一些简单 的方法,有的虽不能保证所取数的和是最大,但确是一个先 取者必胜的策略。
数学模型建立:N个数排成一行,我们给这N个数从左到右编号, 依次为1,2,…,N,因为N为偶数,又因为是我们先取数,计 算机后取数,所以一开始我们既可以取到一个奇编号的数(最 左边编号为1的数)又可以取到一个偶编号的数(最右边编号 为N的数)。 如果我们第一次取奇编号(编号为1)的数,则接着计算机 只能取到偶编号(编号为2或N)的数; 如果我们第一次取偶编号(编号为N)的数,则接着计算机 只能取到奇编号(编号为1或N-1)的数; 即无论我们第一次是取奇编号的数还是取偶编号的数,接着 计算机只能取到另一种编号(偶编号或奇编号)的数。
算法说明
每求出一种面额所需的张数后, 一定要把这部分金额 减去:“GZ=GZ-A*B[j];”,否则将会重复计算。
算法分析
算法的时间复杂性是O(n)。
2、取数游戏
有2个人轮流取2n个数中的n个数,取数之和大者为胜。请 编写算法,让先取数者胜,模拟取数过程。
问题分析
这个游戏一般假设取数者只能看到2n个数中两边的数, 用贪婪算法的情况:
算法设计:有了以上建立的高效数学模型,算法就很简单了,算 法只需要分别计算一组数的奇数位和偶数位的数据之和,然后就 先了取数者就可以确定必胜的取数方式了。 以下面一排数为例: 1 2 3 10 5 6 7 8 9 4 奇编号数之和为25(=1+3+5+7+9),小于偶编号数之和为30 (=2+10+6+8+4)。我们第一次取4,以后,计算机取哪边的数 我们就取哪边的数(如果计算机取1,我们就取2;如果计算机取 9,我们就取8)。这样可以保证我们自始自终取到偶编号的数, 而计算机自始自终取到奇编号的数。
例如,设有11个活动等待安排,这些活动按结束 时间的非减序排列如下:
i 1 2 3 4 5 6 7 8 9 10 11
si
fi
1
4
3
5
0
6
5
7
3
8
5
9
6
10
8
11
8
12
2
13
12
14
3 2
1 1
4 4
7 6 5
活动2、活动3 与活动1不相容 活动4与活动1相容
活动5、活动6、活 动7与活动4不相容
问题:如何选取满足条件iS, jV-S,且c[i][j]最小的 边(i, j), 成了算法难点问题。 解决方法: 设置两个数组closest和lowcost。对于每个j V-S,closest[j]是j在S中的邻接顶点,它与j在S中 的其他邻接顶点k相比较有c[j][closet[j]] ≤c[j][k] 。lowcost[j]的值就是c[j][closest[j]]
算法
main( ) { int i,j,n,GZ,A; int B[8]={0,100,50,20,10,5,2,1},S[8]; input(n); for(i=1;i<=n;i++) { input(GZ); for(j=1,j<=7;j++) { A=GZ/B[j]; S[j]=S[j]+A; GZ=GZ-A*B[j];} } for(i=1;i<=7;i++) print(B[i], “----”, S[i]); }
20
20/30 10/20
50
20 30 10
60 120 50 背包 180
(b) 贪心策略1
20 30 10
190 200
30 10
(a) 三个物品及背包
(c) 贪心策略2 (d) 贪心策略3
7.3.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相容。活动安排问题要求在所给的活动 集合中选出最大的相容活动子集。
a
频率(千次) 定长码 变长码
b 13 001 101
c 12 010 100
d 16 011 111
e 9 100
f 5 101
45 000 0
1101 1100
最小生成树
Prim算法
设G=(V,E)是一个连通带权图, y={l, 2, …, n}。 算法思路: 首先置S={1}, T= Ø .若SV, 就作如下的贪心选择: 选取满足条件iS, jV-S,且c[i][j]最小的边(i, j),将顶点j添加到S中 边(i, j)添加到T中.这个过程一直进行到S=V时为止. T中的所有边构 成G的一棵最小生成树。 算法描述 void Prim(int n, Type * * c) { T= Ø; S ={1}; while (S!= V) { (i, j) = i S且 jV- S的最小权边; T=TU{(i,j)}; S= S U{j}; } }
main( ) {int i,s1,s2,data; input(n); s1=0; s2=0; for(i=1;i<=n;i=i+1) {input( data); if (i mod 2=0) else if(s1>s2) else
s2=s2+data; s1=s1+data; print(“first take left”); print(“first take right”);
换言之,贪心法并不是从整体最优考虑,它所做出的选择只 是在某种意义上的局部最优。这种局部最优选择并不总能获得整 体最优解但通常能获得近似最优解。
该算法适用的问题:
贪婪算法对问题只需考虑当前局部信息就要做出决策,也 就是说使用贪婪算法的前提是“局部最优策略能导致产生全局 最优解”。 该算法的适用范围较小, 若应用不当, 不能保证求得问题 的最佳解。一般情Biblioteka Baidu下通过一些实际的数据例子,就能从直观上 就能判断一个问题是否可以用贪婪算法。更准确的方法是通过 数学方法证明问题对贪婪策略的选用性。
应用第三种贪心策略,每次从物品集合中选择单 位重量价值最大的物品,如果其重量小于背包容量, 就可以把它装入,并将背包容量减去该物品的重量, 然后我们就面临了一个最优子问题——它同样是背包 问题,只不过背包容量减少了,物品集合减少了。因 此背包问题具有最优子结构性质。
例如,有3个物品,其重量分别是{20, 30, 10},价值 分别为{60, 120, 50},背包的容量为50,应用三种贪 心策略装入背包的物品和获得的价值如图所示。
max vi xi
i 1
n
于是,背包问题归结为寻找一个满足约束条 件式,并使目标函数式达到最大的解向量X=(x1, x2, …, xn)。
至少有三种看似合理的贪心策略: (1)选择价值最大的物品,因为这可以尽可能快 地增加背包的总价值。但是,虽然每一步选择获得 了背包价值的极大增长,但背包容量却可能消耗得 太快,使得装入背包的物品个数减少,从而不能保 证目标函数达到最大。 (2)选择重量最轻的物品,因为这可以装入尽可 能多的物品,从而增加背包的总价值。但是,虽然 每一步选择使背包的容量消耗得慢了,但背包的价 值却没能保证迅速增长,从而不能保证目标函数达 到最大。 (3)选择单位重量价值最大的物品,在背包价值 增长和背包容量消耗两者之间寻找平衡。
算法的时间主要消耗在将各个活动按结束时间从小到 大排序。因此,算法的时间复杂性为O(nlog2n)。
哈夫曼编码
哈夫曼编码是广泛地用于数据文件压缩的十分有效的 编码方法。其压缩率通常在20%~90%之间。哈夫曼编 码算法用字符在文件中出现的频率表来建立一个用0, 1串表示各字符的最优表示方式。 给出现频率高的字符较短的编码,出现频率较低的字 符以较长的编码,可以大大缩短总码长。
2 典型贪心算法
1、币种统计问题
某单位给每个职工发工资(精确到元)。为了保证不要临 时兑换零钱, 且取款的张数最少,取工资前要统计出所有职工 的工资所需各种币值(100,50,20,10,5,2,1元共七种)的张数。 请编程完成。
算法设计
1) 从键盘输入每人的工资。 2) 对每一个人的工资,用“贪婪”的思想,先尽量多地取大 面额的币种,由大面额到小面额币种逐渐统计。 3) 利用数组应用技巧,将七种币值存储在数组B。这样,七种 币值就可表示为B[i],i=1,2,3,4,5,6,7。为了能实现贪婪策略, 七种币应该从大面额的币种到小面额的币种依次存储。 4) 利用数组技巧,设置一个有7个元素的累加器数组S。
若一组数据为:6,16,27,6,12,9,2,11,6,5。用贪婪策 略每次两人都取两边的数中较大的一个数,先取者胜.以A先 取为例: 取数结果为: A 6,27,12,5,11=61 胜 B 16,6,9,6,2=39
但若选另一组数据:16,27,7,12,9,2,11,6。仍都用贪婪 算法,先取者A败。 取数结果为: A 16,7,9,11=43 B 27,12,6,2=47 胜
贪心法求解活动安排问题的关键是如何选择贪心策略,使 得按照一定的顺序选择相容活动,并能安排尽量多的活动。至 少有两种看似合理的贪心策略: (1)最早开始时间:这样可以增大资源的利用率。 (2)最早结束时间:这样可以使下一个活动尽早开始。
由于活动占用资源的时间没有限制,因此,后一种贪心选 择更为合理。 为了在每一次贪心选择时快速查找具有最早结束时间的相容 活动,先把n个活动按结束时间非减序排列。这样,贪心选择 时取当前活动集合中结束时间最早的活动就归结为取当前活动 集合中排在最前面的活动。
这个例题又一次说明,解决问题时数学模型的选择是 非常重要的。
3、背包问题
给定n种物品和一个容量为C的背包,物 品i的重量是wi,其价值为vi,背包问题是如何 选择装入背包的物品,使得装入背包中物品的 总价值最大?
设xi表示物品i装入背包的情况,根据问题的要求, 有如下约束条件和目标函数:
n wi xi C i 1 0 xi 1 (1 i n)
这是对第一个回合的分析,显然对以后整个取数过程都适 用。也就是说,我们能够控制让计算机自始自终只取一种编号 的数。这样,我们只要比较奇编号数之和与偶编号数之和谁大, 以决定最开始我们是取奇编号数还是偶编号数即可。(如果奇 编号数之和与偶编号数之和同样大,我们第一次可以任意取数,
因为当两者所取数和相同时,先取者为胜。
贪心算法
1 贪心算法基本思想
2 典型贪心算法
3 哈夫曼树
4 最小生成树
贪心算法
1贪心算法的基本思想
贪心法在解决问题的策略上目光短浅,只根据当前已有的信 息就做出选择,而且一旦做出了选择,不管将来有什么结果,这 个选择都不会改变。从问题的某一个初始解出发逐步逼近给定的 目标,每一步都作一个不可回溯的决策,尽可能地求得最好的解。 当达到某算法中的某一步不需要再继续前进时,算法停止。
1 1
4 4
8 8 9 8 8
6 7 8 9 10 11
活动8与活动4相容 活动9、活动10 与活动1不相容 活动11与活动8相容
10
1 1
0 1 2 3 4
4 4
5
11 11
12 13 14
设有n个活动等待安排,这些活动的开始时间和结束时间 分别存放在数组s[n]和f[n]中,集合B存放问题的解,即选定 的活动集合,算法如下:
∞ b 4 0 a 8 h ∞ 4 b 4 0 a 8 h 8 11 7 11 7
8 ∞ i 6 1 2
∞ c
7
∞ d 14 9 e ∞ 10
4 g ∞
2
f ∞
(a)
8 ∞ i 6 1 g ∞ 2 4 f ∞ ∞ c 7 ∞ d 14 9 e ∞ 10 2
其实,若我们只能看到两边的数据,则此题无论先取还 是后取都无必胜的策略。这时一般的策略是用近似贪婪算法。 但若取数者能看到全部2n个数,则此问题可有一些简单 的方法,有的虽不能保证所取数的和是最大,但确是一个先 取者必胜的策略。
数学模型建立:N个数排成一行,我们给这N个数从左到右编号, 依次为1,2,…,N,因为N为偶数,又因为是我们先取数,计 算机后取数,所以一开始我们既可以取到一个奇编号的数(最 左边编号为1的数)又可以取到一个偶编号的数(最右边编号 为N的数)。 如果我们第一次取奇编号(编号为1)的数,则接着计算机 只能取到偶编号(编号为2或N)的数; 如果我们第一次取偶编号(编号为N)的数,则接着计算机 只能取到奇编号(编号为1或N-1)的数; 即无论我们第一次是取奇编号的数还是取偶编号的数,接着 计算机只能取到另一种编号(偶编号或奇编号)的数。
算法说明
每求出一种面额所需的张数后, 一定要把这部分金额 减去:“GZ=GZ-A*B[j];”,否则将会重复计算。
算法分析
算法的时间复杂性是O(n)。
2、取数游戏
有2个人轮流取2n个数中的n个数,取数之和大者为胜。请 编写算法,让先取数者胜,模拟取数过程。
问题分析
这个游戏一般假设取数者只能看到2n个数中两边的数, 用贪婪算法的情况:
算法设计:有了以上建立的高效数学模型,算法就很简单了,算 法只需要分别计算一组数的奇数位和偶数位的数据之和,然后就 先了取数者就可以确定必胜的取数方式了。 以下面一排数为例: 1 2 3 10 5 6 7 8 9 4 奇编号数之和为25(=1+3+5+7+9),小于偶编号数之和为30 (=2+10+6+8+4)。我们第一次取4,以后,计算机取哪边的数 我们就取哪边的数(如果计算机取1,我们就取2;如果计算机取 9,我们就取8)。这样可以保证我们自始自终取到偶编号的数, 而计算机自始自终取到奇编号的数。
例如,设有11个活动等待安排,这些活动按结束 时间的非减序排列如下:
i 1 2 3 4 5 6 7 8 9 10 11
si
fi
1
4
3
5
0
6
5
7
3
8
5
9
6
10
8
11
8
12
2
13
12
14
3 2
1 1
4 4
7 6 5
活动2、活动3 与活动1不相容 活动4与活动1相容
活动5、活动6、活 动7与活动4不相容
问题:如何选取满足条件iS, jV-S,且c[i][j]最小的 边(i, j), 成了算法难点问题。 解决方法: 设置两个数组closest和lowcost。对于每个j V-S,closest[j]是j在S中的邻接顶点,它与j在S中 的其他邻接顶点k相比较有c[j][closet[j]] ≤c[j][k] 。lowcost[j]的值就是c[j][closest[j]]
算法
main( ) { int i,j,n,GZ,A; int B[8]={0,100,50,20,10,5,2,1},S[8]; input(n); for(i=1;i<=n;i++) { input(GZ); for(j=1,j<=7;j++) { A=GZ/B[j]; S[j]=S[j]+A; GZ=GZ-A*B[j];} } for(i=1;i<=7;i++) print(B[i], “----”, S[i]); }
20
20/30 10/20
50
20 30 10
60 120 50 背包 180
(b) 贪心策略1
20 30 10
190 200
30 10
(a) 三个物品及背包
(c) 贪心策略2 (d) 贪心策略3
7.3.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相容。活动安排问题要求在所给的活动 集合中选出最大的相容活动子集。
a
频率(千次) 定长码 变长码
b 13 001 101
c 12 010 100
d 16 011 111
e 9 100
f 5 101
45 000 0
1101 1100
最小生成树
Prim算法
设G=(V,E)是一个连通带权图, y={l, 2, …, n}。 算法思路: 首先置S={1}, T= Ø .若SV, 就作如下的贪心选择: 选取满足条件iS, jV-S,且c[i][j]最小的边(i, j),将顶点j添加到S中 边(i, j)添加到T中.这个过程一直进行到S=V时为止. T中的所有边构 成G的一棵最小生成树。 算法描述 void Prim(int n, Type * * c) { T= Ø; S ={1}; while (S!= V) { (i, j) = i S且 jV- S的最小权边; T=TU{(i,j)}; S= S U{j}; } }
main( ) {int i,s1,s2,data; input(n); s1=0; s2=0; for(i=1;i<=n;i=i+1) {input( data); if (i mod 2=0) else if(s1>s2) else
s2=s2+data; s1=s1+data; print(“first take left”); print(“first take right”);
换言之,贪心法并不是从整体最优考虑,它所做出的选择只 是在某种意义上的局部最优。这种局部最优选择并不总能获得整 体最优解但通常能获得近似最优解。
该算法适用的问题:
贪婪算法对问题只需考虑当前局部信息就要做出决策,也 就是说使用贪婪算法的前提是“局部最优策略能导致产生全局 最优解”。 该算法的适用范围较小, 若应用不当, 不能保证求得问题 的最佳解。一般情Biblioteka Baidu下通过一些实际的数据例子,就能从直观上 就能判断一个问题是否可以用贪婪算法。更准确的方法是通过 数学方法证明问题对贪婪策略的选用性。
应用第三种贪心策略,每次从物品集合中选择单 位重量价值最大的物品,如果其重量小于背包容量, 就可以把它装入,并将背包容量减去该物品的重量, 然后我们就面临了一个最优子问题——它同样是背包 问题,只不过背包容量减少了,物品集合减少了。因 此背包问题具有最优子结构性质。
例如,有3个物品,其重量分别是{20, 30, 10},价值 分别为{60, 120, 50},背包的容量为50,应用三种贪 心策略装入背包的物品和获得的价值如图所示。
max vi xi
i 1
n
于是,背包问题归结为寻找一个满足约束条 件式,并使目标函数式达到最大的解向量X=(x1, x2, …, xn)。
至少有三种看似合理的贪心策略: (1)选择价值最大的物品,因为这可以尽可能快 地增加背包的总价值。但是,虽然每一步选择获得 了背包价值的极大增长,但背包容量却可能消耗得 太快,使得装入背包的物品个数减少,从而不能保 证目标函数达到最大。 (2)选择重量最轻的物品,因为这可以装入尽可 能多的物品,从而增加背包的总价值。但是,虽然 每一步选择使背包的容量消耗得慢了,但背包的价 值却没能保证迅速增长,从而不能保证目标函数达 到最大。 (3)选择单位重量价值最大的物品,在背包价值 增长和背包容量消耗两者之间寻找平衡。
算法的时间主要消耗在将各个活动按结束时间从小到 大排序。因此,算法的时间复杂性为O(nlog2n)。
哈夫曼编码
哈夫曼编码是广泛地用于数据文件压缩的十分有效的 编码方法。其压缩率通常在20%~90%之间。哈夫曼编 码算法用字符在文件中出现的频率表来建立一个用0, 1串表示各字符的最优表示方式。 给出现频率高的字符较短的编码,出现频率较低的字 符以较长的编码,可以大大缩短总码长。
2 典型贪心算法
1、币种统计问题
某单位给每个职工发工资(精确到元)。为了保证不要临 时兑换零钱, 且取款的张数最少,取工资前要统计出所有职工 的工资所需各种币值(100,50,20,10,5,2,1元共七种)的张数。 请编程完成。
算法设计
1) 从键盘输入每人的工资。 2) 对每一个人的工资,用“贪婪”的思想,先尽量多地取大 面额的币种,由大面额到小面额币种逐渐统计。 3) 利用数组应用技巧,将七种币值存储在数组B。这样,七种 币值就可表示为B[i],i=1,2,3,4,5,6,7。为了能实现贪婪策略, 七种币应该从大面额的币种到小面额的币种依次存储。 4) 利用数组技巧,设置一个有7个元素的累加器数组S。
若一组数据为:6,16,27,6,12,9,2,11,6,5。用贪婪策 略每次两人都取两边的数中较大的一个数,先取者胜.以A先 取为例: 取数结果为: A 6,27,12,5,11=61 胜 B 16,6,9,6,2=39
但若选另一组数据:16,27,7,12,9,2,11,6。仍都用贪婪 算法,先取者A败。 取数结果为: A 16,7,9,11=43 B 27,12,6,2=47 胜
贪心法求解活动安排问题的关键是如何选择贪心策略,使 得按照一定的顺序选择相容活动,并能安排尽量多的活动。至 少有两种看似合理的贪心策略: (1)最早开始时间:这样可以增大资源的利用率。 (2)最早结束时间:这样可以使下一个活动尽早开始。
由于活动占用资源的时间没有限制,因此,后一种贪心选 择更为合理。 为了在每一次贪心选择时快速查找具有最早结束时间的相容 活动,先把n个活动按结束时间非减序排列。这样,贪心选择 时取当前活动集合中结束时间最早的活动就归结为取当前活动 集合中排在最前面的活动。
这个例题又一次说明,解决问题时数学模型的选择是 非常重要的。
3、背包问题
给定n种物品和一个容量为C的背包,物 品i的重量是wi,其价值为vi,背包问题是如何 选择装入背包的物品,使得装入背包中物品的 总价值最大?
设xi表示物品i装入背包的情况,根据问题的要求, 有如下约束条件和目标函数:
n wi xi C i 1 0 xi 1 (1 i n)