0%

最小生成树(Kruskal算法)

####题目描述

输出无向连通图最小生成树权重之和。

####输入

第一行是2个整数,分别表示顶点个数n和边数m。接下来的m行中,每一行第一个整数表示边的开始顶点,第二个表示边的结束顶点,第三个表示这条边的权重。
(测试数据中保证图是连通图;
没有自环;
两个顶点之间只有一条边;
0<权重<100(可以相等);n<=50; m<=1000;)

####输出

输出无向连通图最小生成树权重之和。

####样例输入

1
2
3
4
5
6
7
8
9
10
11
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6

####样例输出

1
15

思路

利用优先队列存储边的信息,并且每次选出最短的边,注意需要重载<,定义优先级:

1
bool operator < (const edge &e) const {return dist > e.dist;}

Component数组维护每个点所在的集合信息,Comonent[i]=s表示顶点i在集合s中。Union函数判断两个点是否在同一集合中,若是,则合并失败返回false;若否,遍历Component数组,将两个顶点所在的集合改为同一个集合,返回true,这个过程复杂度为O(n),应该可以再降吧,我没多想……然后就在主函数中遍历所有的边,把符合条件的边的长度累加就行啦。

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
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
struct edge
{
int start,end,dist;
edge(int s = 0, int e = 0, int d = 0){
start = s; end = e; dist = d;}
bool operator < (const edge &e) const {
return dist > e.dist;}//用于实现优先级的比较函数,默认是functional中的less<T>
};
int main()
{
int n, m;//顶点个数n和边数m
cin >> n >> m;
int** a = new int*[n];
bool* label = new bool[n];
priority_queue<edge> q;
for (int i = 0; i < n; i++)
{
label[i] = 0;
a[i] = new int[n];
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[i][j] = 100;
label[0] = true;
int x, y, d;
for (int i = 0; i < m; i++)
{
cin >> x >> y >> d;
a[x - 1][y - 1] = d;
a[y - 1][x - 1] = d;
if (x == 1 || y == 1)
{
int k = x > y ? x : y;
q.push(edge(0, k - 1, d));//以0为起点
}
}
int res = 0; edge e;
int v = 0;//加入的顶点数
while (!q.empty()&&v<n-1)
{
e = q.top();
q.pop();
if (label[e.end])continue;
res += e.dist;
label[e.end] = true;
++v;
for (int i = 0; i < n; i++){
if (a[e.end][i] < 100&&!label[i])
q.push(edge(e.end, i, a[e.end][i]));
}
}
cout << res << endl;
return 0;
}