题意:
有n个人要回到n间房子里,每间房子只允许一个人,求n个人要走的最小距离和。
分析:
裸的二分图最小权匹配,KM搞之。
代码:
//poj 2195 //sep9 #include <iostream> using namespace std; const int maxN=128; char g[maxN][maxN]; int mx[maxN],my[maxN],hx[maxN],hy[maxN]; int w[maxN][maxN]; int lx[maxN],ly[maxN],linky[maxN]; int visx[maxN],visy[maxN]; int slack[maxN]; int nx,ny; bool find(int x) { visx[x]=true; for(int y=0;y<ny;++y){ if(visy[y]) continue; int t=lx[x]+ly[y]-w[x][y]; if(t==0){ visy[y]=true; if(linky[y]==-1||find(linky[y])){ linky[y]=x; return true; } } else if(slack[y]>t) slack[y]=t; } return false; } int KM() { int i,j; memset(linky,-1,sizeof(linky)); memset(ly,0,sizeof(ly)); for(i=0;i<nx;++i) for(j=0,lx[i]=INT_MIN;j<ny;++j) if(w[i][j]>lx[i]) lx[i]=w[i][j]; for(int x=0;x<nx;++x){ for(i=0;i<ny;++i) slack[i]=INT_MAX; while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(find(x)) break; int d=INT_MAX; for(i=0;i<ny;++i) if(!visy[i]&&slack[i]<d) d=slack[i]; if(d==INT_MAX) return -1; for(i=0;i<nx;++i) if(visx[i]) lx[i]-=d; for(i=0;i<ny;++i) if(visy[i]) ly[i]+=d; else slack[i]-=d; } } int result=0; for(i=0;i<ny;++i) if(linky[i]>-1) result+=w[linky[i]][i]; return result; } int main() { int i,j,n,m; while(scanf("%d%d",&n,&m)==2){ if(n==0&&m==0) break; for(i=0;i<n;++i) scanf("%s",g[i]); int mcnt=0,hcnt=0; for(i=0;i<n;++i) for(j=0;j<m;++j) if(g[i][j]=='m'){ mx[mcnt]=i; my[mcnt]=j; ++mcnt; } else if(g[i][j]=='H'){ hx[hcnt]=i; hy[hcnt]=j; ++hcnt; } for(i=0;i<mcnt;++i) for(j=0;j<hcnt;++j){ w[i][j]=abs(mx[i]-hx[j])+abs(my[i]-hy[j]); w[i][j]=-w[i][j]; } nx=ny=mcnt; printf("%d\n",-KM()); } return 0; }
时间: 2024-12-24 06:37:41