小人和房子一一对应,二分匹配求最小值,可以转化为求最大值,用一个较大的数减去原权值作为边上新的权值,求结果时再用那个较大的数分别减一次 代码: #include<iostream> using namespace std; #define inf 0x3f3f3f3f struct node { int x; int y; }man[105],house[105]; int n,m,n1,n2; bool visx[105],visy[105]; int link[105],slack[105]; int lx[105],ly[105],w[105][105]; bool dfs(int u) { visx[u]=true; int v,x; for(v=1;v<=n1;v++) { if(visy[v]) continue; x=lx[u]+ly[v]-w[u][v]; if(x==0) { visy[v]=true; if(link[v]==-1||dfs(link[v])) { link[v]=u; return true; } } else if(x>0&&slack[v]>x) slack[v]=x; } return false; } void km() { int i,j,min,k,d,res=0; memset(link,-1,sizeof(link)); memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); for(i=1;i<=n1;i++) for(j=1;j<=n1;j++) { if(w[i][j]>lx[i]) lx[i]=w[i][j]; } for(i=1;i<=n1;i++) slack[i]=inf; for(k=1;k<=n1;k++) { while(true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(dfs(k)) break; d=inf; for(i=1;i<=n1;i++) { if(!visy[i]) if(d>slack[i]) d=slack[i]; } for(i=1;i<=n1;i++) { if(visx[i]) lx[i]-=d; } for(i=1;i<=n1;i++) { if(visy[i]) ly[i]+=d; } } } for(i=1;i<=n1;i++) { res+=250-w[link[i]][i]; } printf("%d/n",res); } int main() { int i,j; char c; while(scanf("%d %d",&n,&m)&&m&&n) { memset(w,0,sizeof(w)); memset(house,0,sizeof(house)); memset(man,0,sizeof(man)); n1=n2=0; for(i=1;i<=n;i++) { getchar(); for(j=1;j<=m;j++) { scanf("%c",&c); if(c=='H') { house[++n1].x=i; house[n1].y=j; } else if(c=='m') { man[++n2].x=i; man[n2].y=j; } } } for(i=1;i<=n2;i++) for(j=1;j<=n1;j++) { w[i][j]=250-abs(man[i].x-house[j].x)-abs(man[i].y-house[j].y); } km(); } system("pause"); return 0; }