有 n 個男性和 m 個女性,共 n+m 人。每人有基礎成本 10000。r 條潛在配對,每條配對 (x, y, w) 表示男性 x 和女性 y 配對可節省 w 成本。每人最多屬於一對。求最小總成本。
初始總成本 = (n + m) * 10000。
選擇配對即從圖中選邊,每條邊權重為節省成本 w。
約束:每個頂點度 ≤ 1 (匹配)。
目標:最大化所選邊權重和 → 最大權匹配。
但本題圖為二分圖 (男性集合、女性集合),且無奇環約束,可用克魯斯克爾算法求最大生成森林等價求解!
因此:按 w 降序,若兩端點所在並查集不同,則合並並累加 w 即得最大權匹配!
#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 MAXN = 20005; // n,m ≤ 10000
int fa[MAXN];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m, r;
cin >> n >> m >> r;
vector<Edge> edges;
edges.reserve(r);
for (int i = 0; i < r; ++i) {
int x, y, w;
cin >> x >> y >> w;
edges.push_back({x, y + n, w}); // 女性編號偏移 n
}
sort(edges.begin(), edges.end()); // 按 w 降序
// 初始化並查集
for (int i = 0; i < n + m; ++i) fa[i] = i;
long long saved = 0;
for (auto& e : edges) {
int fu = find(e.u), fv = find(e.v);
if (fu != fv) {
fa[fu] = fv;
saved += e.w;
}
}
long long total = 1LL * (n + m) * 10000 - saved;
cout << total << '\n';
}
return 0;
}
| 技巧 | 說明 |
|---|---|
| 節點重編號 | 女性編號 +n,統一並查集索引 0..n+m-1 |
| 降序排序 | 構建最大生成森林 / 最大權匹配 |
| 並查集判環 | 等價於匹配中「兩端點未被匹配」 |
| 長長整型 | 總成本可達 20000×10000 = 2×10⁸,需 64 位 |
本題是「並查集 + 貪心」解決匹配問題的教科書級範例,展示了圖論中二分圖匹配與生成樹的深刻聯繫。