把边按权值从小到大排序,能连接两个不同连通块就选。
P3366 【模板】最小生成树
GESP8 冲刺课堂页:先建模,再压缩状态,最后读代码。
一、先回答问题
只选每个点最短的一条边,可能形成环或不能连通所有点。
二、核心观察
并查集维护当前连通块;cnt 记录已选边数。
为什么不丢答案:Kruskal 的割性质保证当前最小且不成环的边可以安全加入。
当前边
连通块
已选 cnt
三、互动演示
步骤1
关键状态 A-
关键状态 B-
答案/目标-
复杂度看表
课堂动作手推
点击下一步开始。
四、自己选答案
为什么要按边权排序?
先判断,再点按钮。
cnt 不到 n-1 怎么办?
先判断,再点按钮。
五、手推结果
| 步骤 | 动作 |
|---|---|
| 排序 | 按 w 升序 |
| 扫描 | 不同集合才选 |
| 结束 | cnt==n-1 才有 MST |
课堂要求:每题先说清对象、关系、保留的信息、压缩掉的信息,再写代码。
六、C++14 参考代码
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int u, v, w;
bool operator<(const Edge &other) const {
return w < other.w;
}
};
const int N = 5005;
int fa[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
bool unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return false;
fa[x] = y;
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<Edge> edges(m);
for (int i = 0; i < m; i++) {
cin >> edges[i].u >> edges[i].v >> edges[i].w;
}
sort(edges.begin(), edges.end());
for (int i = 1; i <= n; i++) fa[i] = i;
long long ans = 0;
int cnt = 0;
for (const Edge &e : edges) {
if (unite(e.u, e.v)) {
ans += e.w;
cnt++;
if (cnt == n - 1) break;
}
}
if (cnt == n - 1) cout << ans << '\n';
else cout << "orz\n";
return 0;
}