最小生成树--Prim算法和Kruskal算法
来源:互联网 发布:tensorflow spark 编辑:程序博客网 时间:2024/06/10 00:04
概述
Prim算法和Kruskal算法,是用来求加权连通图的最小生成树的算法。
意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
—————————————————————————————————————————————————————————————————————————————
Prim算法
基本思想
从单一顶点开始,普里姆算法按照以下步骤逐步扩大树中所含顶点的数目,直到遍及连通图的所有顶点。
输入:一个加权连通图,其中顶点集合为V,边集合为E;
初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {};
重复下列操作,直到Vnew = V:
在集合E中选取权值最小的边(u, v),其中u为集合Vnew中的元素,而v则是V中没有加入Vnew的顶点(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
将v加入集合Vnew中,将(u, v)加入集合Enew中;
输出:使用集合Vnew和Enew来描述所得到的最小生成树。
示例:
算法实现:
#include<iostream>using namespace std;const int INF = 999999;const int MAXV = 10000;int vnum, edgenum, start;// 邻接矩阵 int edge[MAXV][MAXV];// 记录Vnew中每个点到V中邻接点的最短边int lowcost[MAXV];// 标记某点是否加入Vnewint addVnew[MAXV];// 记录V中与Vnew最邻近的点int adj[MAXV];void prim(int start){// 最小生成树的权值 int sumweight = 0;int i, j;int k = 0;for(i=1;i<=vnum;++i){lowcost[i] = INF;adj[i] = start;}// 顶点从1开始 for(i=1;i<=vnum;++i){// 将所有点至于Vnew之外,V之内// 这里只要addVnew对应的值为-1,就表示在Vnew之外lowcost[i] = edge[start][i];addVnew[i] = -1;}// 将起始点start加入VnewaddVnew[start] = 0;adj[start] = start;for(i=1;i<=vnum;++i){// 由于从start开始的,因此不需要再对第start个顶点进行处理if(start==i)continue;int min = INF;int v = -1;for(j=1;j<=vnum;++j){// 在Vnew之外寻找最短路径if(addVnew[j]==-1 && lowcost[j]<min){min = lowcost[j];v = j;}}if(v!=-1){// 输出新加入的边 cout<<adj[v]<<" "<<v<<" "<<lowcost[v]<<endl;// 将v加Vnew中addVnew[v] = 0;// 计算路径长度之和sumweight += lowcost[v];for(j=1;j<=vnum;++j){if(addVnew[j]==-1 && edge[v][j]<lowcost[j]){// 此时v点加入Vnew 需要更新lowcostlowcost[j] = edge[v][j];adj[j] = v;}}}}// 输出最小生成树的权值 cout<<sumweight<<endl;}int main(){while(cin>>vnum>>edgenum>>start){for(int i=1;i<=vnum;++i){for(int j=1;j<=vnum;++j){if(i==j)edge[i][j] = 0;elseedge[i][j] = INF;}}int p, q, val;for(int i=1;i<=edgenum;++i){cin>>p>>q>>val;edge[p][q] = val;edge[q][p] = val;}prim(start);}return 0;}
测试案例:
输入
7 11 41 2 71 4 52 3 82 4 92 5 73 5 54 5 154 6 65 6 85 7 96 7 11
输出
4 1 54 6 61 2 72 5 75 3 55 7 939
————————————————————————————————————————————————————————————————————————————
Kruskal算法
基本思想:
按照权值从小到大选择n-1条边,且保证这n-1条边不形成回路。
首先构造一个只含有n个顶点的森林,然后依照权值从小到大从联通网中选择边加入到深林中,并使森林不产生回路,直至森林变成一棵树为止。
示例:
要点:
1)对图的所有边按照权值从小到大进行排序
解决方法:采用排序算法进行排序
2)将边添加到最小生成树中时,判断是否形成了回路
解决方法:记录顶点在最小生成树中的终点,然后每次需要将一条边添加到最小生成树时,判断该边的两个顶点的终点是否重合,重合的话会构成回路。
伪代码:
Kruskal(){ 对边的权值从小到大进行排序; 初始化每个顶点的终点为它自己; 对于所有的边(u,v): 找到顶点u的终点x; 找到顶点v的终点y; 如果(x!=y): 将边(u,v)加入到最小生成树中; 修改顶点u的终点;}
算法实现:
#include<iostream>#include<algorithm>using namespace std;// 最大边的数量 const int MAXE = 20000;// 最大顶点的数量const int MAXV = 20000; // 边的结构体 struct edge{int u, v, cost;};// 数组,用来保存所有的边 edge road[MAXE];// 数组,用来保存对应顶点的终点 int endpoint[MAXV];// sort需要的比较函数 bool cmp(const edge &e1, const edge &e2){ return e1.cost<e2.cost; }// find函数返回顶点x的终点 int find(int x){ if (endpoint[x] == x) return x; else return endpoint[x] = find(endpoint[x]); } // unite函数的结果是将顶点x和顶点y加入到最小生成树中 void unite(int x, int y){ x = find(x); y = find(y); // 终点一样则不发生变化 if (x == y) return; // 否则,修改x的终点为y else endpoint[x] = y; } // init函数的结果是将所有顶点的终点初始化为自己 void init(int vexnum){for(int i=0;i<vexnum;++i)endpoint[i] = i;}int KRUSKAL(int vexnum, int edgenum){// ans用于记录最小生成树的总权值 int ans = 0;// 初始化每个顶点的终点为它自己init(vexnum);// 对边的权值从小到大进行排序sort(road, road+edgenum, cmp);for(int i=0;i<edgenum;i++){ if(find(road[i].u)!=find(road[i].v)){ // 将边(u,v)加入到最小生成树中 // 修改顶点u的终点; unite(road[i].u, road[i].v); ans += road[i].cost; } }return ans;}int main(){int vexnum, edgenum;cin>>vexnum>>edgenum;for(int i=0;i<edgenum;++i){cin>>road[i].u>>road[i].v>>road[i].cost;}cout<<KRUSKAL(vexnum, edgenum)<<endl;return 0;}
测试案例:
输入
7 110 1 70 3 51 2 81 3 91 4 72 4 53 4 153 5 64 5 84 6 95 6 11
输出
39
参考资料:
维基百科、如果天空不死--博客园、华山大师兄--博客园
- 最小生成树--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算法
- 工厂模式(factory Pattern)实现示例demo
- Okhttp 简单理解
- QNX6.50 upgrade with SP1 and patch 3792,4004
- OpenCV3.0 Examples学习笔记(11)-houghcircles.cpp-houghcircles函数实现圆形检测
- spark wordcount
- 最小生成树--Prim算法和Kruskal算法
- 微信小程序全套使用指南
- ARM 汇编指令学习:[2]ARM指令集
- 关于自定义控件之自定义属性篇
- java序列化反序列化原理
- 杂技杂记
- Lucene: 全文检索的基本原理
- flume入门例子
- LeetCode 112 Path Sum