Files
Data-Structure/模板//虚拟节点-完全MST模板.cpp
2025-12-16 20:36:27 +08:00

95 lines
2.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
/*
通用模板:虚拟源点 + Kruskal 求最小生成树
适用场景:
- 每个节点有一个直接购买成本 cost[i]
- 节点之间有全图/部分图的额外边权 w(i,j)
- 最小代价获得所有节点(最小购买成本/最小连通代价)
思想:
- 新建虚拟节点 0
- 向所有节点 i 添加边 (0, i) 权重 cost[i]
- 将所有边 (i, j) 加入
- 对整个图做 MST
*/
struct Edge {
int u, v, w;
bool operator < (const Edge &other) const {
return w < other.w;
}
};
// -------------- DSU并查集模板 --------------
vector<int> parent;
int find(int x) {
return parent[x] == x ? x : parent[x] = find(parent[x]);
}
bool mergeSet(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return false;
parent[x] = y;
return true;
}
// ----------------------------------------------
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N; // 节点数量
cin >> N;
vector<int> cost(N+1); // 每个节点的购买代价,自定义题目可按需求调整
for (int i = 1; i <= N; i++)
cin >> cost[i];
vector<Edge> edges;
// 初始化 DSU节点范围为 0 ~ NN+1 个节点)
parent.resize(N + 1);
for (int i = 0; i <= N; i++) parent[i] = i;
// Step 1添加虚拟源点 0 的边
// 边 (0, i) 表示“直接购买第 i 个节点”
for (int i = 1; i <= N; i++) {
edges.push_back({0, i, cost[i]});
}
// Step 2添加原有图的边
// 例如读取 M 条边 (u, v, w)
int M;
cin >> M;
for (int i = 0; i < M; i++) {
int u, v, w;
cin >> u >> v >> w;
edges.push_back({u, v, w});
}
// Step 3Kruskal MST
sort(edges.begin(), edges.end());
long long result = 0;
int used = 0; // 已加入的边数量
for (auto &e : edges) {
if (mergeSet(e.u, e.v)) {
result += e.w;
used++;
if (used == N) break; // N+1 个节点选 N 条边即可
}
}
cout << result << "\n";
return 0;
}