题目链接:http://poj.org/problem?id=2195
题目大意:
给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。
man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。
解题思路:
将每个man和house建边求最佳匹,KM模板。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5e2+5; const int INF=0x3f3f3f3f; int ny,nx; int lx[N],ly[N],link[N],slack[N],g[N][N]; bool visx[N],visy[N]; struct node{ int x,y; node(){} node(int x,int y):x(x),y(y){} }a[N],b[N]; bool dfs(int x){ visx[x]=true; for(int y=0;y<ny;y++){ if(visy[y]) continue; int tmp=lx[x]+ly[y]-g[x][y]; if(tmp==0){ visy[y]=true; if(link[y]==-1||dfs(link[y])){ link[y]=x; return true; } } else if(slack[y]>tmp) slack[y]=tmp; } return false; } int KM(){ memset(link,-1,sizeof(link)); memset(ly,0,sizeof(ly)); for(int i=0;i<nx;i++){ lx[i]=-INF; for(int j=0;j<ny;j++){ if(g[i][j]>lx[i]) lx[i]=g[i][j]; } } for(int x=0;x<nx;x++){ for(int i=0;i<ny;i++){ slack[i]=INF; } while(true){ memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(dfs(x)) break; int d=INF; for(int i=0;i<ny;i++){ if(!visy[i]&&slack[i]<d) d=slack[i]; } for(int i=0;i<nx;i++){ if(visx[i]) lx[i]-=d; } for(int i=0;i<ny;i++){ if(visy[i]) ly[i]+=d; } } } int ans=0; for(int i=0;i<ny;i++){ if(link[i]!=-1) ans+=g[link[i]][i]; } return ans; } int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ if(n==0&&m==0) break; nx=ny=0; char str[N]; for(int i=0;i<n;i++){ scanf("%s",str); for(int j=0;j<m;j++){ if(str[j]=='m'){ a[nx++]=node(i,j); } else if(str[j]=='H'){ b[ny++]=node(i,j); } } } for(int i=0;i<nx;i++){ for(int j=0;j<ny;j++){ g[i][j]=-(abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)); } } printf("%d ",-KM()); } return 0; }