解题思路:由于招募一个人的费用是已招募士兵的和这个人的最大亲密度,可以看成是:把人当成节点,把关系当做边。招募一个人,就把他加入到图中,那么如何选择这个人呢?由于我们费用取决于边权的最大值,所以将边权取反,跑一个最小生成树即可。
ac代码:由于cin会被卡时间,所以用了scanf。
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
struct edge {
int u, v, w;
}e[50005];
int fa[50005];
int Rank[50005];
bool cmp(const edge& a, const edge& b) {
return a.w < b.w;
}
void init(int n) {
for (int i = 0; i <= n; i++) {
fa[i] = i;
Rank[i] = 0;
}
}
int find(int x) {
if (x != fa[x])return fa[x] = find(fa[x]);
return fa[x];
}
bool same(int x, int y) {
return find(x) == find(y);
}
void unite(int x, int y) {
x = find(x), y = find(y);
if (x == y)return;
if (Rank[x] < Rank[y]) {
fa[x] = y;
}
else {
fa[y] = x;
if (Rank[x] == Rank[y])Rank[x]++;
}
}
int main() {
int t;
cin >> t;
while (t--) {
int n, m, r;
int res = 0;
cin >> n >> m >> r;
for (int i = 1; i <= r; i++) {
int x, y, d;
scanf("%d%d%d", &x, &y, &d);
e[i].u = x; e[i].v = y + n; e[i].w = -d;
}
sort(e + 1, e + r + 1, cmp);
init(n + m);
for (int i = 1; i <= r; i++) {
if (!same(e[i].u, e[i].v)) {
unite(e[i].u, e[i].v);
res += e[i].w;
}
}
cout << (n + m) * 10000 + res << endl;
}
return 0;
}