HDU [2255] 奔小康赚大钱

二分图带权最大匹配的KM算法(朴素版)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
int init(){
	int rv=0,fh=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') fh=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		rv=(rv<<1)+(rv<<3)+c-'0';
		c=getchar();
	}
	return fh*rv;
}
int n,wei[305][305],lx[305],ly[305],match[305];
bool f[305],fx[305],fy[305];
bool hungarian(int u){
	fx[u]=1;
	for(int v=1;v<=n;v++){
		if(!fy[v]&&lx[u]+ly[v]==wei[u][v]){
			fy[v]=1;
			if(!match[v]||hungarian(match[v])){
				match[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	while(~scanf("%d",&n)){
		memset(lx,0,sizeof(lx));
		memset(ly,0,sizeof(ly));
		memset(wei,0,sizeof(wei));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				wei[i][j]=init();
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				lx[i]=max(lx[i],wei[i][j]);
			}
		}
		memset(match,0,sizeof(match));
		for(int i=1;i<=n;i++){
			while(1){
				memset(fx,0,sizeof(fx));
				memset(fy,0,sizeof(fy));
				if(hungarian(i)) break;
				int ma=0x3f3f3f3f;
				for(int k=1;k<=n;k++){
					if(fx[k]){
						for(int j=1;j<=n;j++){
							if(!fy[j]&&(lx[k]+ly[j]-wei[k][j])<ma){
								ma=lx[k]+ly[j]-wei[k][j];
							}
						}
					}
				}
				for(int i=1;i<=n;i++){
					if(fx[i]) lx[i]-=ma;
					if(fy[i]) ly[i]+=ma;
				}
			}
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			if(match[i]) ans+=wei[match[i]][i];
		}
		cout<<ans<<endl;
	}
}