一、AcWing 859. Kruskal算法求最小生成树
【题目描述】
给定一个
n
n
n个点
m
m
m条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible
。
给定一张边带权的无向图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E),其中
V
V
V表示图中点的集合,
E
E
E表示图中边的集合,
n
=
∣
V
∣
,
m
=
∣
E
∣
n=|V|,m=|E|
n=∣V∣,m=∣E∣。
由
V
V
V中的全部
n
n
n个顶点和
E
E
E中
n
−
1
n-1
n−1条边构成的无向连通子图被称为
G
G
G的一棵生成树,其中边的权值之和最小的生成树被称为无向图
G
G
G的最小生成树。
【输入格式】
第一行包含两个整数
n
n
n和
m
m
m。
接下来
m
m
m行,每行包含三个整数
u
,
v
,
w
u,v,w
u,v,w,表示点
u
u
u和点
v
v
v之间存在一条权值为
w
w
w的边。
【输出格式】
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible
。
【数据范围】
1
≤
n
≤
1
0
5
1≤n≤10^5
1≤n≤105
1
≤
m
≤
2
×
1
0
5
1≤m≤2\times 10^5
1≤m≤2×105
图中涉及边的边权的绝对值均不超过
1000
1000
1000。
【输入样例】
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
【输出样例】
6
【代码】
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 100010, M = 200010;
int pre[N];
int n, m;
struct Edge
{
int x, y, w;
bool operator< (const Edge &t) const
{
return w < t.w;
}
}e[M];
int find(int k)
{
if (pre[k] == k) return k;
return pre[k] = find(pre[k]);
}
//kruskal算法思想是每次选择权值最小的边,若该边所连的两个顶点不在一个连通块内则选取该边
int kruskal()
{
sort(e, e + m);
int res = 0, cnt = 0;//cnt记录已选择边的数量
for (int i = 0; i < m; i++)
{
int px = find(e[i].x), py = find(e[i].y);
if (px != py) pre[px] = py, res += e[i].w, cnt++;
//最小生成树的边数为顶点数-1,已生成最小生成树
if (cnt == n - 1) break;
}
if (cnt != n - 1) return INF;//不存在最小生成树
return res;
}
int main()
{
cin >> n >> m;
//初始化并查集
for (int i = 1; i <= n; i++) pre[i] = i;
for (int i = 0; i < m; i++)
cin >> e[i].x >> e[i].y >> e[i].w;
int ans = kruskal();
if (ans == INF) puts("impossible");
else cout << ans << endl;
return 0;
}