题目大意:
解题思路:
本题最大干扰是男女配对,其实这个条件一点用都没有,不要想复杂了(想成了二分图,我一开始就是这么想的。。。。)
题目要求招募n个女兵,m个男兵;但是一共就n个女兵,m个男兵,也就是说全都招募了
解法很明显,让(10000 - di)求和最小,也就是边权di求和最大,就是“最大生成树“;
那么就来实现一下最大生成树算法就行!
最大生成树算法(其实就是最小生成树的变种)
把表达式变形一下就是 10000 * (n + m) + (-d1 - d2 - d3 - d4 - d5…),那么我们只需要求得(-d1 - d2 - d3 - d4…)的最小值即可
我们可以把边权di取反,再基于最小生成树求得的“最小权值和”,就是上述括号里面的最小值
因此,其实本题就是考最小生成树的模板,唯一的不同就是把边权取反
代码(最小生成树模块)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int, int>PII;
typedef map<int, int>MII;
const int N = 500010, M = N * 2, MOD = 1e4, INF = 0x3f3f3f3f;
const double EPS = 1e-6, PI = acos(-1);
//存储每一条边
struct node{
int u, v, w;
bool operator < (const node &temp) const{ //按边权升序
return w < temp.w;
}
}L[N];
//并查集基操
int fa[N];
void init(){
//下标从[0, n + m - 1],原因见下面的注释(重点2)
for(int i = 0; i < n + m; i++) fa[i] = i;
}
int findfa(int x){
return x == fa[x] ? x : fa[x] = findfa(fa[x]);
}
int n, m, R;
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &m, &R);
//因为是多组输入,因此fa数组每次都要先初始化
init();
for(int i = 0; i < R; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
//重点1:边权取反;
//重点2:因为女兵编号是[0, n - 1],男兵编号[0, m - 1],会有重复,因此让男兵编号都加上n,转换到 [n, n + m - 1],这也是init函数中初始化的下标是从[0, n + m)的原因
L[i] = {u, v + n, -w};
}
//排序
sort(L, L + R);
int cnt = 0;
int sum = 0;
//最小生成树模板
for(int i = 0; i < R; i++){
int u = L[i].u, v = L[i].v, w = L[i].w;
int fx = findfa(u), fy = findfa(v);
if(fx != fy){
fa[fx] = fy;
sum += w;
//因为一共有 n + m 个人,所以选中了n + m - 1条边之后就可以结束了
if(++cnt == n + m - 1) break;
}
}
//输出总价格,注意sum是负数,因此是 +sum
printf("%d\n", (n + m) * 10000 + sum);
}
return 0;
}
总结
其实本题就是考察最小生成树的模板运用
难点在于:
- 能否辨认出二分图是干扰条件,不要陷入
- 能否想到用我们熟悉的最小生成树算法实现“最大生成树”
如果觉得对你有帮助,不妨点个👍吧(逃~~~)