最小生成树的算法分为 prim和kruscal算法
初始状态:
设置2个数据结构:
lowcost[i]:表示以i为终点的边的最小权值,当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了MST
mst[i]:表示对应lowcost[i]的起点,即说明边<mst[i],i>是MST的一条边,当mst[i]=0表示起点i加入MST
我们假设V1是起始点,进行初始化(*代表无限大,即无通路):
lowcost[2]=6,lowcost[3]=1,lowcost[4]=5,lowcost[5]=*,lowcost[6]=*
mst[2]=1,mst[3]=1,mst[4]=1,mst[5]=1,mst[6]=1,(所有点默认起点是V1)
明显看出,以V3为终点的边的权值最小=1,所以边<mst[3],3>=1加入MST
此时,因为点V3的加入,需要更新lowcost数组和mst数组:
lowcost[2]=5,lowcost[3]=0,lowcost[4]=5,lowcost[5]=6,lowcost[6]=4
mst[2]=3,mst[3]=0,mst[4]=1,mst[5]=3,mst[6]=3
明显看出,以V6为终点的边的权值最小=4,所以边<mst[6],6>=4加入MST
此时,因为点V6的加入,需要更新lowcost数组和mst数组:
lowcost[2]=5,lowcost[3]=0,lowcost[4]=2,lowcost[5]=6,lowcost[6]=0
mst[2]=3,mst[3]=0,mst[4]=6,mst[5]=3,mst[6]=0
明显看出,以V4为终点的边的权值最小=2,所以边<mst[4],4>=4加入MST
此时,因为点V4的加入,需要更新lowcost数组和mst数组:
lowcost[2]=5,lowcost[3]=0,lowcost[4]=0,lowcost[5]=6,lowcost[6]=0
mst[2]=3,mst[3]=0,mst[4]=0,mst[5]=3,mst[6]=0
明显看出,以V2为终点的边的权值最小=5,所以边<mst[2],2>=5加入MST
此时,因为点V2的加入,需要更新lowcost数组和mst数组:
lowcost[2]=0,lowcost[3]=0,lowcost[4]=0,lowcost[5]=3,lowcost[6]=0
mst[2]=0,mst[3]=0,mst[4]=0,mst[5]=2,mst[6]=0
很明显,以V5为终点的边的权值最小=3,所以边<mst[5],5>=3加入MST
lowcost[2]=0,lowcost[3]=0,lowcost[4]=0,lowcost[5]=0,lowcost[6]=0
mst[2]=0,mst[3]=0,mst[4]=0,mst[5]=0,mst[6]=0
至此,MST构建成功,如图所示:
1 #include <iostream> 2 3 using namespace std; 4 5 #define MAX 100 6 #define MAXCOST 0xfffffff 7 8 int graph[MAX][MAX]; 9 int lowcost[MAX]; 10 int mst[MAX]; 11 int n,sum = 0; 12 13 int prim() 14 { 15 int min,minid; 16 for (int i=2;i<=n;i++) 17 { 18 lowcost[i] = graph[1][i]; 19 mst[i] = 1; 20 } 21 mst[1] = 0; 22 for (int i=2;i<=n;i++) 23 { 24 min = MAXCOST; 25 minid = 0; 26 for (int j=2;j<=n;j++) 27 { 28 if (lowcost[j] < min && lowcost[j]!=0) 29 { 30 min = lowcost[j]; 31 minid = j; 32 } 33 } 34 sum += min; 35 lowcost[minid] = 0; 36 for (int j=2;j<=n;j++) 37 { 38 if (graph[minid][j] < lowcost[j]) 39 { 40 lowcost[j] = graph[minid][j]; 41 mst[j] = minid; 42 } 43 } 44 } 45 return sum; 46 } 47 48 int main() 49 { 50 int m; 51 cin >> n >> m; // n代表图的顶点,m代表图的边 52 //初始化图 53 for (int i=1;i<=n;i++) 54 { 55 for (int j=1;j<=n;j++) 56 { 57 graph[i][j] = MAXCOST; 58 } 59 } 60 //构造图 61 for (int k=1;k<=m;k++) 62 { 63 int i,j,cost; 64 cin >> i >> j >> cost; 65 graph[i][j] = graph[j][i] = cost; 66 } 67 cout << prim() << endl; 68 return 0; 69 }
kruscal算法 是使用了并查集。始终选择当前可用的最小边权的边(可以直接快排或者algorithm的sort)。每次选择边权最小的边链接两个端点是kruskal的规则,并实时判断两个点之间有没有间接联通。
同样的,模拟过程
对权值进行排序,随后选取最小对权值的边。
排序后,最小的边自然是第8条边,于是4和6相连
遍历继续,第二小的边是1号,1和2联通。
再继续
继续
其次是dis为15的边4,但是2和4已经相连了,pass。
然后是dis为16的两条边(边2和边9),边2连接1和3,边9连接3和6,它们都已经间接相连,pass。
再然后就是dis为22的边10,它连接5和6,5还没有加入组织,所以使用这边。继续,发现此时已经连接了n-1条边,结束,最后图示如下:
魏队的板子:
1 #include <math.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <string.h> 8 #include <vector> 9 #include <map> 10 #include <stack> 11 #include <set> 12 #include <queue> 13 14 15 #define LL long long 16 #define INF 0x3f3f3f3f 17 #define ls nod<<1 18 #define rs (nod<<1)+1 19 const int maxn = 2e5+7; 20 const double eps = 1e-9; 21 22 int n,m,ans,cnt,fa[5050]; 23 24 struct node{ 25 int u, v, w; 26 }e[maxn]; 27 28 bool cmp(node a, node b) 29 { 30 return a.w < b.w; 31 } 32 33 int fid(int x) 34 { 35 return x == fa[x] ? x : fid(fa[x]); 36 } 37 38 bool unite(int r1, int r2)///冰茶鸡 39 { 40 int fidroot1 = fid(r1), fidroot2 = fid(r2); 41 if(fidroot1 != fidroot2) { 42 fa[fidroot2] = fidroot1; 43 return true; 44 } 45 return false; 46 } 47 48 49 void init(int n) 50 { 51 for(int i = 1; i <= n; i++) { 52 fa[i] = i; 53 } 54 ans = 0; 55 cnt = 0; 56 } 57 58 void kruskal() 59 { 60 std::sort(e+1, e+m+1, cmp); 61 for(int i = 1; i <= m; i++) { 62 int eu = fid(e[i].u); 63 int ev = fid(e[i].v); 64 if(eu == ev) { 65 continue; 66 } 67 ans += e[i].w; 68 fa[ev] = eu; 69 if(++cnt == n-1) { 70 break; 71 } 72 } 73 }