最小生成树

最小生成树

1. Kruskal算法

Kruskal算法的思想比Prim好理解一些。

  1. 先把边按照权值进行排序,

  2. 用贪心的思想优先选取权值较小的边,并依次连接,

  3. 若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。

证明:刚刚有提到:如果某个连通图属于最小生成树,那么所有从外部连接到该连通图的边中的一条最短的边必然属于最小生成树。所以不难发现,当最小生成树被拆分成彼此独立的若干个连通分量的时候,所有能够连接任意两个连通分量的边中的一条最短边必然属于最小生成树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void kruskal()
{
sort(edge_set,edge_set+m,cmp);
for(int i=0;i<m;i++)
{
fax=find(edge_set[i].a);
fay=find(edge_set[i].b);
if(fax!=fay)
{
ans += edge_set[i].weight;
fa[fax] = fay;
cnt++;
}
if (cnt==n-1)
{
flag=1;
break;
}
}

}

例题:

【模板】最小生成树

题目描述

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

输入格式

第一行包含两个整数 N,MN,M,表示该图共有 NN 个结点和 MM 条无向边。

接下来 MM 行每行包含三个整数 Xi,Yi,ZiX_i,Y_i,Z_i,表示有一条长度为 ZiZ_i 的无向边连接结点 Xi,YiX_i,Y_i

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

样例 #1

样例输入 #1

1
2
3
4
5
6
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

样例输出 #1

1
7

提示

数据规模:

对于 20%20\% 的数据,N5N\le 5M20M\le 20

对于 40%40\% 的数据,N50N\le 50M2500M\le 2500

对于 70%70\% 的数据,N500N\le 500M104M\le 10^4

对于 100%100\% 的数据:1N50001\le N\le 50001M2×1051\le M\le 2\times 10^51Zi1041\le Z_i \le 10^4

样例解释:

所以最小生成树的总边权为 2+2+3=72+2+3=7

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
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
typedef struct {
int a;
int b;
int weight;
}edge;
edge edge_set[200001];
int fa[5005];
int n, m, u, v, w,cnt=0,fax,fay,ans=0,flag=0;
bool cmp(edge p,edge q)
{
return p.weight<q.weight;
}
int find(int x)
{
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
void kruskal()
{
sort(edge_set,edge_set+m,cmp);
for(int i=0;i<m;i++)
{
fax=find(edge_set[i].a);
fay=find(edge_set[i].b);
if(fax!=fay)
{
ans += edge_set[i].weight;
fa[fax] = fay;
cnt++;
}
if (cnt==n-1)
{
flag=1;
break;
}
}

}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
cin>>u>>v>>w;
edge temp;
temp.a=u;
temp.b=v;
temp.weight=w;
edge_set[i]=temp;
}
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
kruskal();
if(flag==0)cout<<"orz"<<endl;
else printf("%d",ans);
}