题解 P1559 【运动员最佳匹配问题】
通过我仔细的观察,下面只有一篇是用了km算法,但是并不是c++,那我就来写一篇c++的KM算法吧。 这就是一道KM的裸题,边权就是P[i][j]* Q[i][j],然后跑一边KM,这道题就完啦。
不要问KM算法啥玩意,那应该是在博客里学习的内容。
这个写的可以(https://www.cnblogs.com/wenruo/p/5264235.html)
但是我写的要比他简洁一点,仔细看看过程吧。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int a[25][25];//边权
int lx[25],ly[25];//顶标
int visx[25],visy[25];//标记
int pi[25];//记录匹配对象
int n;
int minz;//记录最小的改变量
bool dfs(int s){
visx[s]=1;
for(int i=1;i<=n;i++)
if(!visy[i]){
int t=lx[s]+ly[i]-a[s][i];
if(t==0){
visy[i]=1;
if(pi[i]==0||dfs(pi[i])){
pi[i]=s;
return true;
}
}else if(t>0){
minz=min(minz,t);
}
}
return false;
}
void km(){
for(int i=1;i<=n;i++){
while(1){
minz=100000000;
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(i))break;
for(int j=1;j<=n;j++)
if(visx[j])lx[j]-=minz;
for(int j=1;j<=n;j++)
if(visy[j])ly[j]+=minz;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int r;
scanf("%d",&r);
a[j][i]*=r;
//这个肯定是要倒过来的,仔细读题
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
lx[i]=max(lx[i],a[i][j]);//顶标预处理
km();
int ans=0;
for(int i=1;i<=n;i++)
ans+=a[pi[i]][i];//累加答案
printf("%d",ans);
return 0;
}