NewCodeTemplate
This commit is contained in:
94
模板/图/虚拟节点-完全MST模板.cpp
Normal file
94
模板/图/虚拟节点-完全MST模板.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#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 ~ N(N+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 3:Kruskal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user