在一个地图上给出房子的位置和人的位置,人和房子的数量是相等的。人要回到房子里,每个房子只能回一个人。人向房子每移动一个单位需要花费$1,求人全部回房子的最小花费。
ACcode:
#pragma warning(disable:4786)//使命名长度不受限制
#pragma comment(linker, "/STACK:102400000,102400000")//手工开栈
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rds(x) scanf("%s",x)
#define rdc(x) scanf("%c",&x)
#define ll long long int
#define maxn 105
#define mod 1000000007
#define INF 0x3f3f3f3f //int 最大值
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
#define PI acos(-1.0)
#define E exp(1)
using namespace std;
struct P{int x,y;};
P man[maxn],house[maxn];
int mm,hh,n,m,res;
int a[maxn],b[maxn],match[maxn],slack[maxn],mp[maxn][maxn];
bool visa[maxn],visb[maxn];
char str[maxn];
bool find_path(int u){
visa[u]=true;
FOR(j,0,hh-1){
if(!visb[j]&&a[u]+b[j]==mp[u][j]){
visb[j]=true;
if(match[j]==-1||find_path(match[j])){
match[j]=u;
return true;
}
}
else if(a[u]+b[j]>mp[u][j])
slack[j]=min(slack[j],a[u]+b[j]-mp[u][j]);
}
return false;
}
void km(){
MT(a,0);MT(b,0);MT(match,-1);
FOR(i,0,mm-1)
FOR(j,0,hh-1)
a[i]=max(mp[i][j],a[i]);
FOR(i,0,mm-1){
FOR(j,0,hh-1)slack[j]=INF;
while(true){
FOR(j,0,maxn){visa[j]=visb[j]=0;}
if(find_path(i))break;
int d=INF;
FOR(j,0,hh-1)
if(!visb[j]&&d>slack[j])d=slack[j];
FOR(j,0,mm-1)
if(visa[j])a[j]-=d;
FOR(j,0,hh-1)
if(visb[j])b[j]+=d;
else slack[j]-=d;
}
}
}
int main(){
while(rd2(n,m)&&(n+m)){
hh=mm=res=0;
FOR(i,0,n-1){
rds(str);
FOR(j,0,m-1){
if(str[j]=='H'){
house[hh].x=i;
house[hh++].y=j;
}else if(str[j]=='m'){
man[mm].x=i;
man[mm++].y=j;
}
}
}
FOR(i,0,mm-1)
FOR(j,0,hh-1)
mp[i][j]=-(abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y));
km();
FOR(j,0,hh-1)
res-=mp[match[j]][j];
printf("%d\n",res);
}
return 0;
}
/*
2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0
*/