洛谷P3366 【模板】最小生成树(Kruskal && Prim)

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz

输入输出格式

输入格式:

第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)

接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi

输出格式:

输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz

输入输出样例

输入样例#1: 
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例#1: 
7

说明

时空限制: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 }
Kruskal

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 }
Prim
 
原文地址:https://www.cnblogs.com/lipeiyi520/p/10340376.html