其他分享
首页 > 其他分享> > 题解0015:【模板】最小生成树

题解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