KM算法
易错点:
- 配不上的话可能连机会都没有了,所以不要太天真(vb[y]=1(占有)要在配得上(gap==0,门当户对)的前提下).
- 没缘分的话最好就不要妄想(if(vb[y])continue;).
费用流算法
(qwq)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=310,INF=1<<30;
int la[N],lb[N],w[N][N],match[N],delta,n;
bool va[N],vb[N];
bool dfs(int x){
va[x]=1;
for(int y=1;y<=n;y++){
if(vb[y])continue;
int gap=la[x]+lb[y]-w[x][y];
if(gap==0){
vb[y]=1;
if(!match[y]||dfs(match[y])){
match[y]=x;
return 1;
}
}else delta=min(delta,gap);
}
return 0;
}
int KM(){
for(int x=1;x<=n;x++){
la[x]=-INF;
for(int y=1;y<=n;y++)
la[x]=max(la[x],w[x][y]);
}
for(int x=1;x<=n;x++){
while(1){
memset(va,0,sizeof(va));
memset(vb,0,sizeof(vb));
delta=INF;
if(dfs(x))break;
for(int i=1;i<=n;i++){
if(va[i])la[i]-=delta;
if(vb[i])lb[i]+=delta;
}
}
}
int ans=0;
for(int y=1;y<=n;y++)
ans+=w[match[y]][y];
return ans;
}
void init(){
memset(lb,0,sizeof(lb));
memset(match,0,sizeof(match));
}
int main(){
while(scanf("%d",&n)!=EOF){
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&w[i][j]);
printf("%d\n",KM());
}
return 0;
}