UVA11383 Golden Tiger Claw KM算法
题目链接:传送门
分析
这道题乍看上去没有思路,但是我们仔细一想就会发现这道题其实是一个二分图最大匹配的板子
我们可以把这道题想象成将男生和女生之间两两配对,使他们的好感度最大
我们把矩阵中的元素\(a[x][y]\)看成女生\(x\)和男生\(y\)之间的好感度,跑一个KM算法
因为KM算法会维护\(ex_{}boy[x] + ex_{}girl[y]>=love[y][x]\),所以最后的结果就是我们想要的
注意有多组数据
代码
#include<bits/stdc++.h>
using namespace std;
#define hzoi 0
const int maxn=505;
int love[maxn][maxn];
int ex_girl[maxn],ex_boy[maxn];
bool vis_girl[maxn],vis_boy[maxn];
int match[maxn],slack[maxn];
int n;
bool dfs(int girl){
vis_girl[girl]=1;
for(int boy=1;boy<=n;boy++){
if(vis_boy[boy]) continue;
int gap=ex_girl[girl]+ex_boy[boy]-love[girl][boy];
if(gap==0){
vis_boy[boy]=1;
if(match[boy]==-1 || dfs(match[boy])){
match[boy]=girl;
return 1;
}
} else {
slack[boy]=min(slack[boy],gap);
}
}
return 0;
}
void KM(){
memset(match,-1,sizeof(match));
memset(ex_boy,0,sizeof(ex_boy));
for(int i=1;i<=n;i++){
ex_girl[i]=love[i][1];
for(int j=2;j<=n;j++){
ex_girl[i]=max(love[i][j],ex_girl[i]);
}
}
for(int i=1;i<=n;i++){
memset(slack,0x3f,sizeof(slack));
while(1){
memset(vis_boy,0,sizeof(vis_boy));
memset(vis_girl,0,sizeof(vis_girl));
if(dfs(i)) break;
int d=0x3f3f3f3f;
for(int j=1;j<=n;j++){
if(!vis_boy[j]) d=min(d,slack[j]);
}
for(int j=1;j<=n;j++){
if(vis_girl[j]) ex_girl[j]-=d;
if(vis_boy[j]) ex_boy[j]+=d;
else slack[j]-=d;
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
memset(love,0,sizeof(love));
memset(ex_girl,0,sizeof(ex_girl));
memset(ex_boy,0,sizeof(ex_boy));
memset(vis_girl,0,sizeof(vis_girl));
memset(vis_boy,0,sizeof(vis_boy));
memset(match,0x3f,sizeof(match));
memset(slack,-1,sizeof(slack));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&love[i][j]);
}
}
KM();
int ans=0;
for(int i=1;i<=n;i++){
if(i==1) printf("%d",ex_girl[i]);
else printf(" %d",ex_girl[i]);
ans+=ex_girl[i];
}
printf("\n");
for(int i=1;i<=n;i++){
if(i==1) printf("%d",ex_boy[i]);
else printf(" %d",ex_boy[i]);
ans+=ex_boy[i];
}
printf("\n%d\n",ans);
}
return 0;
}