题目
这是个模板题 链接:P3366
【模板】最小生成树 ## 题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。
输入格式
第一行包含两个整数 $ N,M $ ,表示该图共有 $ N $ 个结点和 $ M $
条无向边。 接下来 $ M $ 行每行包含三个整数 $ X_i,Y_i,Z_i $
,示有一条长度为 $ Z_i $ 的无向边连接结点 $ X_i,Y_i $。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出
orz。
数据规模
对于 20% 的数据,$ N≤5,M≤20 $ 。
对于 40% 的数据,$ N≤50,M≤2500 $ 。
对于 70% 的数据,$ N≤500,M≤10 $ 。
对于 100%100% 的数据:$ 50001≤N≤5000, 1≤M≤2×10^5 $ 。
题解
Kruskal 算法的主要思路: 1. 先以边的权值来给边排序,从小到大
- 然后开始由小到大遍历边,也就是一步一步的点的扩展
- 然后判断这个点的是否在已拓展的点内,如果不在就将答案加上它的边权,并且加入并查集
注意一下,这个是用邻接表edge写的(u,v为边的两个点,为边权),没有用领接矩阵
基本上这个模板就这样了,代码如下:
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 65 66 67 68 69 70
| #include<cstdio> #include<iostream> #include<algorithm>
using namespace std;
struct edge{ int u,v,w; };
edge e[200005]; int father[5005]; int ans = 0;
bool cmp(const edge& a,const edge& b){ return a.w < b.w; }
int found(int x){ return father[x] == x ? x : father[x] = found(father[x]); }
int main() { int n,m;
cin>>n>>m;
for(int i = 1;i <= m;i++) { scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w); }
sort(e,e+m,cmp);
for(int j = 1;j<=n;j++) father[j] = j;
int k = 0; for(int j = 1;j<=m;j++) { if(k == n - 1) break; int v = e[j].v,u = e[j].u; if(found(v) != found(u)) { k++; ans += e[j].w; int f = found(v),t = found(u); father[t] = f; } }
int cnt = 0; for(int i = 1;i<=n;i++) if(father[i] == i) cnt++; if(cnt == 1) cout<<ans<<endl; else cout<<"orz"<<endl; getchar();getchar(); return 0; }
|