ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:25.98KB ,
资源ID:17859272      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-17859272.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(中国数学建模编程交流贪婪算法2.docx)为本站会员(b****2)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

中国数学建模编程交流贪婪算法2.docx

1、中国数学建模编程交流贪婪算法2中国数学建模-编程交流-贪婪算法 数学思想 编程交流 学术杂谈 English Fans wh-ee 重登录 隐身 用户控制面板 搜索 风格 论坛状态 论坛展区 社区服务 社区休闲 网站首页 退出 VC+,C,Perl,Asp.编程学习,算法介绍. 我的收件箱 (0) 中国数学建模 学术区 编程交流 贪婪算法 您是本帖的第 890 个阅读者 * 贴子主题:贪婪算法 b 等级:职业侠客 文章:470 积分:956 门派:黑客帝国 注册:2003-8-28 第 11 楼 1.3.6 最小耗费生成树 在例1 - 2及1 - 3中已考察过这个问题。因为具有n 个顶点的无向

2、网络G的每个生成树刚好具有n-1条边,所以问题是用某种方法选择n-1条边使它们形成G的最小生成树。至少可以采用三种不同的贪婪策略来选择这n-1条边。这三种求解最小生成树的贪婪算法策略是: K r u s k a l算法,P r i m算法和S o l l i n算法。 1. Kruskal算法 (1) 算法思想 K r u s k a l算法每次选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。注意到所选取的边若产生环路则不可能形成一棵生成树。K r u s k a l算法分e 步,其中e 是网络中边的数目。按耗费递增的顺序来考虑这

3、e 条边,每次考虑一条边。当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。 考察图1-12a 中的网络。初始时没有任何边被选择。图13-12b 显示了各节点的当前状态。边( 1 , 6)是最先选入的边,它被加入到欲构建的生成树中,得到图1 3 - 1 2 c。下一步选择边( 3,4)并将其加入树中(如图1 3 - 1 2 d所示)。然后考虑边( 2,7 ),将它加入树中并不会产生环路,于是便得到图1 3 - 1 2 e。下一步考虑边( 2,3)并将其加入树中(如图1 3 - 1 2 f所示)。在其余还未考虑的边中,(7,4)具有最小耗费,因此先考虑它,将它加入

4、正在创建的树中会产生环路,所以将其丢弃。此后将边( 5,4)加入树中,得到的树如图13-12g 所示。下一步考虑边( 7,5),由于会产生环路,将其丢弃。最后考虑边( 6,5)并将其加入树中,产生了一棵生成树,其耗费为9 9。图1 - 1 3给出了K r u s k a l算法的伪代码。 / /在一个具有n 个顶点的网络中找到一棵最小生成树 令T为所选边的集合,初始化T= 令E 为网络中边的集合 w h i l e(E )&(| T |n- 1 ) 令(u,v)为E中代价最小的边 E=E- (u,v) / /从E中删除边 i f( (u,v)加入T中不会产生环路)将( u,v)加入T i f(

5、| T | = =n-1) T是最小耗费生成树 e l s e 网络不是互连的,不能找到生成树 图13-13 Kruskao算法的伪代码 (2) 正确性证明 利用前述装载问题所用的转化技术可以证明图1 3 - 1 3的贪婪算法总能建立一棵最小耗费生成树。需要证明以下两点: 1) 只要存在生成树,K r u s k a l算法总能产生一棵生成树; 2) 产生的生成树具有最小耗费。令G为任意加权无向图(即G是一个无向网络)。从1 2 . 11 . 3节可知当且仅当一个无向图连通时它有生成树。而且在Kruskal 算法中被拒绝(丢弃)的边是那些会产生环路的边。删除连通图环路中的一条边所形成的图仍是连

6、通图,因此如果G在开始时是连通的,则T与E中的边总能形成一个连通图。也就是若G开始时是连通的,算法不会终止于E= 和| T |0) 为在T中而不在U中的边的个数,当然k 也是在U中而不在T中的边的数目。 通过把U变换为T来证明U与T具有相同的耗费,这种转化可在k 步内完成。每一步使在T而不在U中的边的数目刚好减1。而且U的耗费不会因为转化而改变。经过k 步的转化得到的U将与原来的U具有相同的耗费,且转化后U中的边就是T中的边。由此可知, T具有最小耗费。每步转化包括从T中移一条边e 到U中,并从U中移出一条边f。边e 与f 的选取按如下方式进行: 1) 令e 是在T中而不在U中的具有最小耗费的

7、边。由于k 0,这条边肯定存在。 2) 当把e 加入U时,则会形成唯一的一条环路。令f 为这条环路上不在T中的任意一条边。 由于T中不含环路,因此所形成的环路中至少有一条边不在T中。 从e 与f 的选择方法中可以看出, V=U+ e - f 是一棵生成树,且T中恰有k- 1条边不在V中出现。现在来证明V的耗费与U的相同。显然,V的耗费等于U的耗费加上边e 的耗费再减去边f 的耗费。若e 的耗费比f 的小,则生成树V的耗费比U的耗费小,这是不可能的。如果e 的耗费高于f,在K r u s k a l算法中f 会在e 之前被考虑。由于f 不在T中,Kruskal 算法在考虑f 能否加入T时已将f

8、丢弃,因此f 和T中耗费小于或等于f 的边共同形成环路。通过选择e,所有这些边均在U中,因此U肯定含有环路,但是实际上这不可能,因为U是一棵生成树。e 的代价高于f 的假设将会导致矛盾。剩下的唯一的可能是e 与f 具有相同的耗费,由此可知V与U的耗费相同。 (3) 数据结构的选择及复杂性分析 为了按耗费非递减的顺序选择边,可以建立最小堆并根据需要从堆中一条一条地取出各边。当图中有e 条边时,需花(e) 的时间初始化堆及O ( l o ge) 的时间来选取每一条边。边的集合T与G中的顶点一起定义了一个由至多n 个连通子图构成的图。用顶点集合来描述每个子图,这些顶点集合没有公共顶点。为了确定边(

9、u,v)是否会产生环路,仅需检查u,v 是否在同一个顶点集中(即处于同一子图)。如果是,则会形成一个环路;如果不是,则不会产生环路。因此对于顶点集使用两个F i n d操作就足够了。当一条边包含在T中时,2个子图将被合并成一个子图,即对两个集合执行U n i o n操作。集合的F i n d和U n i o n操作可利用8 . 1 0 . 2节的树(以及加权规则和路径压缩)来高效地执行。F i n d操作的次数最多为2e,Un i o n操作的次数最多为n- 1(若网络是连通的,则刚好是n- 1次)。加上树的初始化时间,算法中这部分的复杂性只比O (n+e) 稍大一点。 对集合T所执行的唯一操

10、作是向T中添加一条新边。T可用数组t 来实现。添加操作在数组 的一端进行,因为最多可在T中加入n- 1条边,因此对T的操作总时间为O (n)。 总结上述各个部分的执行时间,可得图1 3 - 1 3算法的渐进复杂性为O (n+el o ge)。 (4) 实现 利用上述数据结构,图1 - 1 3可用C + +代码来实现。首先定义E d g e N o d e类(见程序1 3 - 6 ),它是最小堆的元素及生成树数组t 的数据类型 - plot(100+t+15*cos(3.05*t),t=0.200,coords=polar,axes=none,scaling=constrained); 2004

11、-5-27 19:42:37 b 等级:职业侠客 文章:470 积分:956 门派:黑客帝国 注册:2003-8-28 第 12 楼 程序13-6 Kruskal算法所需要的数据类型 template class EdgeNode p u b l i c : operator T() const return weight; p r i v a t e : T weight;/边的高度 int u, v;/边的端点 ; 为了更简单地使用8 . 1 0 . 2节的查找和合并策略,定义了U n i o n F i n d类,它的构造函数是程序8 - 1 6的初始化函数,U n i o n是程序8

12、- 1 6的加权合并函数,F i n d是程序8 - 1 7的路径压缩搜索函数。 为了编写与网络描述无关的代码,还定义了一个新的类U N e t Wo r k,它包含了应用于无向网络的所有函数。这个类与U n d i r e c t e d类的差别在于U n d i r e c t e d类中的函数不要求加权边,而U N e t Wo r k要求边必须带有权值。U N e t Wo r k中的成员需要利用N e t w o r k类中定义的诸如B e g i n和N e x t Ve r t e x的遍历函数。不过,新的遍历函数不仅需要返回下一个邻接的顶点,而且要返回到达这个顶点的边的权值。这

13、些遍历函数以及有向和无向加权网络的其他函数一起构成了W N e t w o r k类(见程序1 3 - 7)。 程序13-7 WNetwork类 template class WNetwork : virtual public Network public : virtual void First(int i, int& j, T& c)=0; virtual void Next(int i, int& j, T& c)=0; ; 象B e g i n和N e x t Ve r t e x一样,可在A d j a c e n c y W D i g r a p h及L i n k e d W

14、D i g r a p h类中加入函数F i r s t与N e x t。现在A d j a c e n c y W D i g r a p h及L i n k e d W D i g r a p h类都需要从W N e t Wo r k中派生而来。由于A d j a c e n c y W G r a p h类和L i n k e d W G r a p h类需要访问U N e t w o r k的成员,所以这两个类还必须从U N e t Wo r k中派生而来。U N e t Wo r k : : K r u s k a l的代码见程序1 3 - 8,它要求将Edges() 定义为N e

15、t Work 类的虚成员,并且把U N e t Wo r k定义为E d g e N o d e的友元)。如果没有生成树,函数返回f a l s e,否则返回t r u e。注意当返回true 时,在数组t 中返回最小耗费生成树。 程序13-8 Kr u s k a l算法的C + +代码 template bool UNetwork:Kruskal(EdgeNode t) / 使用K r u s k a l算法寻找最小耗费生成树 / 如果不连通则返回false / 如果连通,则在t 0 : n - 2 中返回最小生成树 int n = Ve r t i c e s ( ) ; int e =

16、 Edges(); / /设置网络边的数组 InitializePos(); / 图遍历器 EdgeNode *E = new EdgeNode e+1; int k = 0; / E的游标 for (int i = 1; i = n; i+) / 使所有边附属于i int j; T c; First(i, j, c); while (j) / j 邻接自i if (i j) / 添加到达E的边 E+k.weight = c; Ek.u = i; Ek.v = j; Next(i, j, c); / 把边放入最小堆 MinHeapEdgeNode H(1); H.Initialize(E, e

17、, e); UnionFind U(n); / 合并/搜索结构 / 根据耗费的次序来抽取边 k = 0; / 此时作为t的游标 while (e & k n - 1) / 生成树未完成,尚有剩余边 EdgeNode x; H.DeleteMin(x); / 最小耗费边 e - - ; int a = U.Find(x.u); int b = U.Find(x.v); if (a != b) / 选择边 tk+ = x; U . U n i o n ( a , b ) ; D e a c t i v a t e P o s ( ) ; H . D e a c t i v a t e ( ) ;

18、return (k = n - 1); 2. Prim算法 与Kr u s k a l算法类似,P r i m算法通过每次选择多条边来创建最小生成树。选择下一条边的贪婪准则是:从剩余的边中,选择一条耗费最小的边,并且它的加入应使所有入选的边仍是一棵树。最终,在所有步骤中选择的边形成一棵树。相反,在Kruskal 算法中所有入选的边集合最终形成一个森林。 P r i m算法从具有一个单一顶点的树T开始,这个顶点可以是原图中任意一个顶点。然后往T中加入一条代价最小的边( u , v)使TÈ (u , v) 仍是一棵树,这种加边的步骤反复循环直到T中包含n- 1条边。注意对于边( u

19、, v),u、v 中正好有一个顶点位于T中。P r i m算法的伪代码如图1 -1 4所示。在伪代码中也包含了所输入的图不是连通图的可能,在这种情况下没有生成树。图1 - 1 5显示了对图1-12a 使用P r i m算法的过程。把图1 - 1 4的伪代码细化为C + +程序及其正确性的证明留作练习(练习3 1)。 / /假设网络中至少具有一个顶点 设T为所选择的边的集合,初始化T= 设T V为已在树中的顶点的集合,置T V= 1 令E为网络中边的集合 w h i l e(E ) & & (| T | n-1) 令(u , v)为最小代价边,其中u T V, v T V i f(没有这种边)

20、b re a k E=E- (u,v) / /从E中删除此边 在T中加入边( u , v) if (| T | = =n- 1 ) T是一棵最小生成树 else 网络是不连通的,没有最小生成树 图13-14 Prim最小生成树算法 如果根据每个不在T V中的顶点v 选择一个顶点n e ar (v),使得n e ar (v) Î TV 且c o st (v, n e ar (v) )的值是所有这样的n e ar (v) 节点中最小的,则实现P r i m算法的时间复杂性为O (n2 )。下一条添加到T中的边是这样的边:其cost (v, near (v) 最小,且v T V。 3.

21、Sollin算法 S o l l i n算法每步选择若干条边。在每步开始时,所选择的边及图中的n个顶点形成一个生成树的森林。在每一步中为森林中的每棵树选择一条边,这条边刚好有一个顶点在树中且边的代价最小。将所选择的边加入要创建的生成树中。注意一个森林中的两棵树可选择同一条边,因此必须多次复制同一条边。当有多条边具有相同的耗费时,两棵树可选择与它们相连的不同的边,在这种情况下,必须丢弃其中的一条边。开始时,所选择的边的集合为空。若某一步结束时仅剩下一棵树或没有剩余的边可供选择时算法终止。 图1 - 6给出了初始状态为图1-12a 时,使用S o l l i n算法的步骤。初始入选边数为0时的情形

22、如图13-12a 时,森林中的每棵树均是单个顶点。顶点1,2,.,7所选择的边分别是(1.6), (2,7),(3,4), (4,3), (5,4), (6,1), (7,2),其中不同的边是( 1 , 6 ),( 2 , 7 ),(3,4) 和( 5 , 4 ),将这些边加入入选边的集合后所得到的结果如图1 3 - 1 6 a所示。下一步具有顶点集 1 , 6 的树选择边( 6 , 5 ),剩下的两棵树选择边( 2 , 3 ),加入这两条边后已形成一棵生成树,构建好的生成树见图1 3 - 6 b。S o l l i n算法的C + +程序实现及其正确性证明留作练习(练习3 2 )。 - pl

23、ot(100+t+15*cos(3.05*t),t=0.200,coords=polar,axes=none,scaling=constrained); 2004-5-27 19:42:54 b 等级:职业侠客 文章:470 积分:956 门派:黑客帝国 注册:2003-8-28 第 13 楼 练习 8. 针对装载问题,扩充贪婪算法,考虑有两条船的情况,算法总能产生最优解吗? 9. 已知n 个任务的执行序列。假设任务i 需要ti 个时间单位。若任务完成的顺序为1,2,.,n,则任务i 完成的时间为ci =i åj = 1tj 。任务的平均完成时间(Av e rge Completi

24、on Time, ACT) 为1nn åi = 1ci 。 1) 考虑有四个任务的情况,每个任务所需时间分别是( 4,2,8,1)。若任务的顺序为1,2,3,4,则A C T是多少? 2) 若任务顺序为2,1,4,3,则A C T是多少? 3) 创建具有最小A C T的任务序列的贪婪算法分n 步来构造该任务序列,在每一步中,从剩下的任务里选择时间最小的任务。对于1 ),利用这种策略获得的任务顺序为4,2,1,3,这种顺序的A C T是多少? 4) 写一个C + +程序实现3) 中的贪婪策略,程序的复杂性应为O (nl o gn),试证明之。 5) 证明利用3) 中的贪婪算法获得的任

25、务顺序具有最小的A C T。 10. 若有两个工人执行练习9中的n个任务,需将任务分配给他们,同时他们具有自己的任务执行顺序。任务完成时间及A C T的定义同练习9。使A C T最小化的一种可行的贪婪算法是:两个工人轮流选择任务,每次从剩余的任务中选择时间最小的任务。每个人按照自己所选任务的顺序执行任务。对于练习9中的例子,假定工人1首先选择任务4,然后工人2选择任务2,工人1选择任务1,最后工人2选择任务3。 1) 利用C + +程序实现这种策略,其时间复杂性为多少? 2) 上述的贪婪策略总能获得最小的A C T吗?证明结论。 11. 1) 考虑有m 个人可以执行任务,扩充练习1 0中的贪婪

26、算法。 2) 算法能保证获得最优解吗?证明结论。 3) 用C + +程序实现此算法,其复杂性是多少? 12. 考虑例4 - 4的堆栈折叠问题。 1) 设计一个贪婪算法,将堆栈折叠为最小数目的子堆栈,使得每个子堆栈的高度均不超过H。 2) 算法总能保证得到数目最少的子堆栈吗?证明结论。 3) 用C + +代码实现1) 的算法。 4) 代码的时间复杂性是多少? 13. 编写C + +程序实现0 / 1背包问题,使用如下启发式方法:按价值密度非递减的顺序打包。 14. 根据k= 1的性能受限启发式方法编写一个C + +程序来实现0 / 1背包问题。 15. 对于k= 1的情况证明用性能受限的启发式方

27、法求解0 / 1背包问题会发生边界错误。 16. 根据k= 2的性能受限启发式方法编写一个C + +程序来实现0 / 1背包问题。 17. 考虑0xi 1而不是xi Î 0 , 1 的连续背包问题。一种可行的贪婪策略是:按价值密度非递减的顺序检查物品,若剩余容量能容下正在考察的物品,将其装入;否则,往背包中装入此物品的一部分。 1) 对于n=3, w=100,10,10, p= 2 0 , 1 5 , 1 5 及c= 1 0 5 ,上述装入方法获得的结果是什么? 2) 证明这种贪婪算法总能获得最优解。 3) 用一个C + +程序实现此算法。 18. 例1 3 - 1的渴婴问题是练习

28、1 7中连续背包问题的一般化,将练习1 7的贪婪算法用于渴婴问题,算法能保证总能得到最优解吗?证明结论。 19. 1) 证明当且仅当二分图没有覆盖时,图1 3 - 7的算法找不到覆盖。 2) 给出一个具有覆盖的二分图,使得图1 3 - 7的算法找不到最小覆盖。 20. 当第一步选择了顶点1时,给出图1 3 - 7的工作过程。 21. 对于二分图覆盖问题设计另外一种贪婪启发式方法,可使用如下贪婪准则:如果B中的某一个顶点仅被A中一个顶点覆盖,选择A中这个顶点;否则,从A中选择一个顶点,使得它所覆盖的未被覆盖的顶点数目最多。 1) 给出这种贪婪算法的伪代码。 2) 编写一个C + +函数作为U n

29、 d i r e c t e d类的成员来实现上述贪婪算法。 3) 函数的复杂性是多少? 4) 验证代码的正确性。 22. 令G为无向图,S为G中顶点的子集,当且仅当S中的任意两个顶点都有一条边相连时,S为完备子图(c l i q u e),完备子图的大小即S中的顶点数目。最大完备子图( maximum clique)即具有最大项点数目的完备子图。在图中寻找最大完备子图的问题(即最大完备子图问题)是一个N P-复杂问题。 1) 给出最大完备子图问题的一种可行的贪婪算法及其伪代码。 2) 给出一个能用1) 中的启发式算法求解最大完备子图的图例,以及不能用该算法求解的一个图例。 3) 将1) 中的启发式算法实现为Undirected:Clique(int C, int m) 共享成员,其中最大完备子图的大小返回到m中,最大完备子图的顶点返回到C中。 4) 代码的复杂性是多少? 23. 令G为一无向图,S为G中顶点的子集,当且仅当S中任意两个顶点都无边相连时, S为无关集(independent set)。最大无关集即是顶点数目最多的无关集。在一幅图中寻找最大无关集是一个N P-复杂问

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2