题目地址


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;
}