HDU [P1533]

二分图带权最小匹配(朴素)

只要换几个不等号的方向就行,不需要变换权值的正负

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,m,wei[105][105],lx[105],ly[105],match[105];
bool fx[105],fy[105];
struct point{
	int x,y;
}men[105],hou[105];
bool hungarian(int u){
	fx[u]=1;
	for(int v=1;v<=m;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(1){
		int row,col;
		cin>>row>>col;
		if(!row&&!col) break;
		n=m=0;
		for(int i=1;i<=row;i++){
			for(int j=1;j<=col;j++){
				char t;
				scanf(" %c ",&t);	
				if(t=='m') men[++n].x=i,men[n].y=j;
				if(t=='H') hou[++m].x=i,hou[m].y=j;
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
			//	printf("%d %d %d %d\n",men[i].x,men[i].y,hou[j].x,hou[j].y); 
				wei[i][j]=abs(men[i].x-hou[j].x)+abs(men[i].y-hou[j].y);
			}
		}
		memset(lx,0x3f,sizeof(lx));                  //
		memset(ly,0,sizeof(ly));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				lx[i]=min(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 mi=-0x3f3f3f3f;           //
				for(int k=1;k<=n;k++){
					if(fx[k]){
						for(int j=1;j<=m;j++){
							if(!fy[j]&&(lx[k]+ly[j]-wei[k][j])>mi){   //
								mi=lx[k]+ly[j]-wei[k][j];
							}
						}
					}
				}
				for(int i=1;i<=n;i++){
					if(fx[i]) lx[i]-=mi;
				}
				for(int i=1;i<=m;i++){
					if(fy[i]) ly[i]+=mi;
				}
			}
		}
		int ans=0;
		for(int i=1;i<=m;i++){
			if(match[i]) ans+=wei[match[i]][i];
			//cout<<ans<<endl;
		}
		cout<<ans<<endl;
	}
}
posted @ 2018-01-17 11:55  Mr_Wolfram  阅读(180)  评论(0编辑  收藏  举报