最小生成树:Prim算法和Kruskal算法
来源:互联网 发布:js根据日期计算星期几 编辑:程序博客网 时间:2024/05/19 00:52
介绍
在实际生活中,我们经常碰到类似这样的一类问题:假设要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,我们需要考虑这样一个问题,如何在最节省经费前提下建立这个通信网.换句话说,我们需要在这n个城市中找出一个包含所有城市的连通子图,使得其所有边的经费之和最小.
这个问题可以转换为一个图论的问题:图中的每个节点看成是一个城市,节点之间的无向边表示修建该路的经费,即每条边都有其相应的权值,而我们的目标是挑选n-1条边使所有节点保持连通,并且要使得经费之和最小.
这里存在一个显而易见的事实是:最优解中必然不存在循环(可通过反证法证明).因此,最后找出的包含所有城市的连通子图必然没有环路。这种连通且没有环路的连通图就简称为树,而在一个连通图中删除所有的环路而形成的树叫做该图的生成树.对于城市建立通信连通网,需要找出的树由于具有最小的经费之和,因此又被称为最小生成树(Minimum Cost Spanning Tree),简称MST.
解法
由于生成树必须包含原图里面的所有节点,关键的问题就在于边的选择,怎么才能找出n-1条边,使得所有节点连通,并且权重最小呢?这里,我们先来看看MST有什么特点.
设有上图所示的最小生成树T,如果删除边(u,v)∈T,则T将被分解成两个子树:T1和T2,因此,T1和T2分别是其所包含节点的最小生成树,此处可用反证法证明:如果T1(也可假设为T2)不是其所包含节点的最小生成树,那么,势必还存在的生成树T',那么,T'+w(u,v)+T2<T1+w(u,v)+T2,这与我们的假设T是最小生成树相矛盾,故结论成立.
这就是最小生成树的最优子结构性质,在细想一下,MST也包含了重叠子问题的性质,那么似乎我们可以用动态规划来解决.但如果用动态规划来解决MST,其时间复杂度是指数级别的,显然不是太可取,我们需要找寻更好的方法.既然MST满足最优子结构性质,那么它是否满足贪婪选择属性呢?
设图G=(V,E),U是顶点集V的一个非空子集,如果(u,v)是一条具有最小权值的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树.
上述的性质可以通过反证法证明,如果(u,v)不包含在G的最小生成树T中,那么,T的路径中必然存在一条连通U和V-U的边,如果将这条边以(u,v)来替换,我们将获得一个权重更低的生成树,这与T是最小生成树矛盾.
既然MST满足贪婪选择属性,那么,求解最小生成树的问题就简化了很多。总结一下,具体的步骤大概如下:
- 构建一棵空的最小生成树T,并将所有节点赋值为无穷大.
- 任选一个节点放入T,另外一个节点集合为V-T.
- 对V-T中节点的赋值进行更新(由于此时新加入一个节点,这些距离可能发生变化)
- 从V-T中选择赋值最小的节点,加入T中
- 如果V-T非空,继续步骤3~5,否则算法终结.
#include<algorithm>#define INF INT_MAX#define MAX_V 1000int cost[MAX_V][MAX_V];int min_cost[MAX_V];bool vis[MAX_V];//vert表示的顶点的个数int prim(int vert){ fill(vis,vis+vert,false); fill(min_cost,min_cost+vert,INF); min_cost[0] = 0 ; int res = 0 ; while(true) { int v = -1 ; for(int i=0;i!=vert;++i) if(!vis[i] && (v==-1 || min_cost[i] < min_cost[v])) v = i ; if(v==-1) break; res +=min_cost[v]; vis[v] = true; for(int i=0;i!=vert;++i) //此处的写法只是一种简便的写法,对于已加入vis[i]=true的顶点 //即使更新到它也不会出错,请注意上面循环中的!vis[i]这个条件 min_cost[i] = min(min_cost[i],cost[v][i]); } return res;}
#include<iostream>#include<algorithm>#define MAX_E 10000#define MAX_V 110using namespace std;struct Edge{ int from,to,cost; void set(int f,int t,int c) { from = f , to = t , cost = c ; } bool operator<(const Edge& t) const { return cost < t.cost; }}e[MAX_E];int f[MAX_V];int Find(int x){ return x==f[x] ? x : f[x] = Find(f[x]) ;}bool Union(int x,int y){ int fx = Find(x),fy = Find(y); if(fx==fy) return false; f[fx] = fy ; return true;}//vert表示的是顶点的个数inline void init_find_union(int vert){ for(int i=0;i!=vert;++i) f[i] = i ;}//vert:顶点的个数//e_num:边的条数int Kruskal(int vert,int e_num){ int cnt = vert - 1 ,res = 0 ; init_find_union(vert); sort(e,e+e_num); for(int i=0;cnt && i!=e_num;++i) if(Union(e[i].from,e[i].to)) res +=e[i].cost; return res;}
- 最小生成树--Prim和Kruskal算法
- 最小生成树 prim算法和kruskal
- 最小生成树Prim和Kruskal算法
- 最小生成树算法:prim和kruskal
- 最小生成树 ,prim 和Kruskal 算法
- 最小生成树prim和kruskal算法
- Kruskal和Prim--最小生成树算法
- 最小生成树算法 :Prim算法 和 Kruskal 算法
- 最小生成树算法—Kruskal算法和Prim算法
- 最小生成树-Kruskal算法-Prim算法
- 最小生成树 Prim算法 Kruskal算法
- 最小生成树Prim算法Kruskal算法
- 最小生成树Prim算法,Kruskal算法
- 最小生成树(Prim算法和Kruskal算法)
- [最小生成树]Prim算法和Kruskal算法
- 最小生成树(Prim算法和Kruskal算法)
- 最小生成树—kruskal算法和prim算法
- 最小生成树:Prim算法和Kruskal算法
- 第十七章 Spring 事件处理(Spring Framework3.1教程)
- UML九中图总结
- 世界上最短的数字判断代码
- 学习计算机
- HDU 1880 魔咒词典
- 最小生成树:Prim算法和Kruskal算法
- document.body.clientHeight 和 document.documentElement.clientHeight 的区别
- js 实现全选和反选
- 在UBuntu下搭建LAMP
- 一款树形表格的插件TreeGrid
- 第十八章 Spring中定制事件(Spring Framework3.1教程)
- windows 内核编程总结
- 结构体互相指向
- 6572_message_MWI (Message Waiting Information)