95 lines
2.1 KiB
C++
95 lines
2.1 KiB
C++
#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;
|
||
}
|