前言

删繁就简。。。就用最小生成树。。。

1.思想

这里使用的是Kruskal算法。

  • 首先,MST的用途是在一个有n个点的无向图里,选出(n-1)条变组成一个新的连通图,求最小边权值。
  • 用并查集来维护图的连通性;
  • 将所有边按边权值从小到大排序;
  • 如果一条边连接的两个点不在一个并查集里,用这条边连接这两个点。
  • 因为是按边权值升序排序的,所以可以保证每次选取的都是最小边权值的边。

    2.最小生成树模板题

    【题目链接】
    洛谷【3366】
    【题目描述】
    如题,给出一个无向图,求出最小生成树。(原题说如果不连通则输出orz,然而并没有输出orz的点。。。)
    【输入格式】
    第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
    接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
    【输出格式】
    输出包含一个数,即最小生成树的各边的长度之和。
    【输入样例】

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 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
65
66
67
68
69
70
71
72
73
#include<cstdio>
#include<iostream>
#include<algorithm>
#define M 500500
using namespace std;
int n,m,ans;
struct E{
int from,to,w;
}e[M];
int tope;
inline void ae(int x,int y,int z)
{
tope++;e[tope].to=y;e[tope].from=x;e[tope].w=z;
}
int fa[M];
inline void reinit()
{
for(int i=1;i<=n;++i)
{
fa[i]=i;
}
}
int find(int x)
{
if(x!=fa[x])
fa[x]=find(fa[x]);
return fa[x];
}
int pd(int x,int y)
{
if(find(x)==find(y)) return 1;
return 0;
}
inline void un(int x,int y)
{
fa[find(x)]=find(y);
}
int cmp(E x,E y)
{
return x.w<y.w;
}
int main()
{
scanf("%d%d",&n,&m);
int ta,tb,tc;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&ta,&tb,&tc);
ae(ta,tb,tc);
}
sort(e+1,e+tope+1,cmp);
reinit();
for(int i=1;i<=tope;++i)
{
if(pd(e[i].from,e[i].to)==0)
{
un(e[i].from,e[i].to);
ans+=e[i].w;
}
}
printf("%d",ans);
return 0;
}