洛谷P3366 【模板】最小生成树(Kruskal && Prim)
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入输出样例
说明
时空限制:1000ms,128M
数据规模:
对于20%的数据:N<=5,M<=20
对于40%的数据:N<=50,M<=2500
对于70%的数据:N<=500,M<=10000
对于100%的数据:N<=5000,M<=200000
Kruskal:
将m条边按边权从小到大排序,枚举每条边,如果该边的起点和终点已经在最小生成树中,则跳过,否则就将这条边加入到最小生成树中。具体实现方面会借助于并查集,来判断两个点是否在最小生成树中(已连通)。//边
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int n,m; 5 struct kkk{ 6 int qd,zd,len; 7 }bian[200001]; 8 bool cmp(kkk a,kkk b) {//按照边权大小排序 9 return a.len < b.len; 10 } 11 int f[5001]; 12 int getf(int o) {//找父亲 13 if(o == f[o]) return o; 14 return f[o] = getf(f[o]); 15 } 16 int main(){ 17 cin >> n >> m; 18 for(int i = 1;i <= m; i++) 19 cin >> bian[i].qd >> bian[i].zd >> bian[i].len; 20 sort(bian+1,bian+m+1,cmp); 21 for(int i = 1;i <= n;i++) 22 f[i] = i; 23 int ans = 0; 24 for(int i = 1;i <= m; i++) { 25 int p1 = bian[i].qd; 26 int p2 = bian[i].zd; 27 int f1 = getf(p1); 28 int f2 = getf(p2); 29 if(f1 != f2) {//判断两个点是否在一个集合里 ,如果不在,就加上一条边 30 ans += bian[i].len; 31 f[f1] = f2; 32 } 33 } 34 cout<<ans; 35 return 0; 36 }
Prim:
将所有点分在两个集合中,a集合中存已经被连入最小生成树中的点,b集合中存还没在最小生成树中的点 。
开始时a为空,将所有点放到b里。任选一个点为根放到a中,并找到一条a集合到b集合最短的一条边,边两端的节点不定,但必须保证分别在a,b两个集合中,我们可以用并查集维护。将这条边b集合的端点放到a集合,答案加上这条边,直至b集合为空。//点
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,m,g[5001][5001],x,y,v,dis[5001],ans; 8 bool b[5001]; 9 10 void prim() { 11 for(int i = 0;i <= n; i++) dis[i] = g[1][i]; 12 dis[1] = 0; 13 b[1] = true; 14 for(int i = 1;i < n; i++) { 15 int k = 0; 16 for(int j = 1;j <= n; j++) 17 if(!b[j] && dis[j] < dis[k]) k = j; 18 b[k] = true; 19 ans += dis[k]; 20 for(int j = 1;j <= n; j++) { 21 if(dis[j] > g[k][j]) 22 dis[j] = g[k][j]; 23 } 24 } 25 } 26 27 int main() { 28 scanf("%d%d",&n,&m); 29 memset(g,0x3f,sizeof(g)); 30 for(int i = 0;i <= n; i++) g[i][i] = 0; 31 for(int i = 1;i <= m; i++) { 32 scanf("%d%d%d",&x,&y,&v); 33 g[x][y] = g[y][x] = min(g[x][y],v); 34 } 35 prim(); 36 printf("%d",ans); 37 return 0; 38 }