题解0015:【模板】最小生成树
作者:互联网
题目链接:https://www.luogu.com.cn/problem/P3366
题目描述:给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。
做这道题我们可以用两种算法:
1.普里姆算法
先找到一个点,遍历这个点的所有临边,找到最小权值的边并合并为一个集合,不断循环下去。
2.克鲁斯卡尔算法
将所有边按权值排序,从小到大遍历这些边,将两端点合并(需要一些特殊判断),最终找到最小生成树。
本篇题解用克鲁斯卡尔算法来做这道题。
同时还需要用到一个判断两点是否在同一集合的算法——并查集算法。
就是让同一集合内的所有点指向同一个父节点的算法。
上代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct Q{//存储两点一边的结构体 4 int a,b,c; 5 }; 6 int n,m,fa[5005],we,wer,wert=0; 7 Q q[200001]; 8 bool cmp(Q a,Q b){ 9 return a.c<b.c;//按边的权值排序 10 } 11 int find(int x){//并查集算法 12 while(x!=fa[x]){//如果一个点不指向它的父节点 13 x=fa[x]=fa[fa[x]];//让它指向它向上两级的父节点(三点即为一个三角形,所以这里只需要指向上两级) 14 } 15 return x; 16 } 17 void kruskal(){//克鲁斯卡尔算法 18 sort(q,q+m,cmp); 19 for(int i=0;i<m;i++){ 20 int ea=find(q[i].a); 21 int eb=find(q[i].b);//找两个端点的父节点 22 if(ea==eb){//如果两个端点的父节点相同,也就是两点同属一个点集合,那就不要这条边了 23 continue; 24 } 25 we+=q[i].c;//加上权值 26 fa[ea]=eb;//将两个集合合并 27 wer++; 28 if(wer==n-1){//如果找到的边=点数-1,说明找到了 29 return; 30 } 31 } 32 cout<<"orz";//这个orz可坑啊,还要定义变量存储状态,要不然会打出两个数 33 wert=1; 34 } 35 int main(){ 36 cin>>n>>m; 37 for(int i=1;i<=n;i++){ 38 fa[i]=i; 39 } 40 for(int i=0;i<m;i++){ 41 cin>>q[i].a>>q[i].b>>q[i].c; 42 } 43 kruskal(); 44 if(wert!=0){ 45 return 0; 46 } 47 cout<<we; 48 return 0; 49 }
标签:0015,return,int,题解,最小,算法,权值,模板 来源: https://www.cnblogs.com/wdrdsahudhisjabshdahuhsh/p/16439441.html