题目地址:
https://www.luogu.com.cn/problem/P3366
题目描述:
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
。
输入格式:
第一行包含两个整数
N
,
M
N,M
N,M,表示该图共有
N
N
N个结点和
M
M
M条无向边。接下来
M
M
M行每行包含三个整数
X
i
,
Y
i
,
Z
i
X_i,Y_i,Z_i
Xi,Yi,Zi,表示有一条长度为
Z
i
Z_i
Zi的无向边连接结点
X
i
,
Y
i
X_i,Y_i
Xi,Yi。
输出格式:
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出orz
。
数据范围:
对于
20
%
20\%
20%的数据,
N
≤
5
N≤5
N≤5,
M
≤
20
M≤20
M≤20。
对于
40
%
40\%
40%的数据,
N
≤
50
N≤50
N≤50,
M
≤
2500
M\le 2500
M≤2500。
对于
70
%
70\%
70%的数据,
N
≤
500
N≤500
N≤500,
M
≤
1
0
4
M\le 10^4
M≤104。
对于
100
%
100\%
100%的数据:
1
≤
N
≤
5000
1≤N≤5000
1≤N≤5000,
1
≤
M
≤
2
×
1
0
5
1\le M\le 2\times 10^5
1≤M≤2×105。
最小生成树主要有两种算法可以做,一种是Kruskal算法,另一种是Prim算法。
Kruskal算法可以参考https://blog.csdn.net/qq_46105170/article/details/116085555。代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5010, M = 2e5 + 10;
int n, m;
struct Edge {
int a, b, w;
bool operator<(const Edge & t) const {
return w < t.w;
}
} e[M];
int p[N];
int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> m;
for (int i = 0; i < m; i++)
cin >> e[i].a >> e[i].b >> e[i].w;
sort(e, e + m);
for (int i = 1; i <= n; i++) p[i] = i;
int res = 0, cnt = 0;
for (int i = 0; i < m; i++) {
int px = find(e[i].a), py = find(e[i].b);
if (px != py) {
p[px] = py;
res += e[i].w;
cnt++;
}
}
if (cnt < n - 1) cout << "orz" << endl;
else cout << res << endl;
return 0;
}
时间复杂度 O ( m log m ) O(m\log m) O(mlogm),空间 O ( n ) O(n) O(n)。
Prim算法可以参考https://blog.csdn.net/qq_46105170/article/details/116084174。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 5010, M = 2e5 + 10, INF = 0x3f3f3f3f;
int n, m;
int g[N][N], dist[N];
bool st[N];
int prim() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
int res = 0;
// n次循环,每次将一个距离已选点集合最近的点加入集合
for (int i = 1; i <= n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
// 有点不可达,说明不存在最小生成树,返回-1
if (dist[t] == INF) return -1;
st[t] = true;
res += dist[t];
for (int j = 1; j <= n; j++)
if (!st[j] && dist[j] > g[t][j])
dist[j] = g[t][j];
}
return res;
}
int main() {
cin >> n >> m;
memset(g, 0x3f, sizeof g);
while (m--) {
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b], c);
}
int res = prim();
if (res == -1) cout << "orz" << endl;
else cout << res << endl;
return 0;
}
时间复杂度 O ( n 2 ) O(n^2) O(n2),空间 O ( n ) O(n) O(n)。