最小生成树
1. Kruskal算法
Kruskal算法的思想比Prim好理解一些。
-
先把边按照权值进行排序,
-
用贪心的思想优先选取权值较小的边,并依次连接,
-
若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
证明:刚刚有提到:如果某个连通图属于最小生成树,那么所有从外部连接到该连通图的边中的一条最短的边必然属于最小生成树。所以不难发现,当最小生成树被拆分成彼此独立的若干个连通分量的时候,所有能够连接任意两个连通分量的边中的一条最短边必然属于最小生成树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void kruskal() { sort(edge_set,edge_set+m,cmp); for(int i=0;i<m;i++) { fax=find(edge_set[i].a); fay=find(edge_set[i].b); if(fax!=fay) { ans += edge_set[i].weight; fa[fax] = fay; cnt++; } if (cnt==n-1) { flag=1; break; } }
}
|

例题:
【模板】最小生成树
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。
输入格式
第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 Xi,Yi,Zi,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz。
样例 #1
样例输入 #1
1 2 3 4 5 6
| 4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3
|
样例输出 #1
提示
数据规模:
对于 20% 的数据,N≤5,M≤20。
对于 40% 的数据,N≤50,M≤2500。
对于 70% 的数据,N≤500,M≤104。
对于 100% 的数据:1≤N≤5000,1≤M≤2×105,1≤Zi≤104。
样例解释:

所以最小生成树的总边权为 2+2+3=7。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <iostream> #include <string.h> #include <vector> #include <algorithm> using namespace std; typedef struct { int a; int b; int weight; }edge; edge edge_set[200001]; int fa[5005]; int n, m, u, v, w,cnt=0,fax,fay,ans=0,flag=0; bool cmp(edge p,edge q) { return p.weight<q.weight; } int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void kruskal() { sort(edge_set,edge_set+m,cmp); for(int i=0;i<m;i++) { fax=find(edge_set[i].a); fay=find(edge_set[i].b); if(fax!=fay) { ans += edge_set[i].weight; fa[fax] = fay; cnt++; } if (cnt==n-1) { flag=1; break; } }
} int main() { cin>>n>>m; for(int i=0;i<m;i++) { cin>>u>>v>>w; edge temp; temp.a=u; temp.b=v; temp.weight=w; edge_set[i]=temp; } for(int i=1;i<=n;i++) { fa[i]=i; } kruskal(); if(flag==0)cout<<"orz"<<endl; else printf("%d",ans); }
|
Harbin Institute of Technology, Shenzhen 计算机科学与技术 本科在读