POJ2195 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。题意来源:http://blog.csdn.net/lyy289065406/article/details/6732762
最小费用取相反数 转化为带权最大匹配:
//最小费用转化为最大匹配
//KM算法
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define Maxn 120
struct Node{
int x,y;
}g[Maxn],h[Maxn];
int map[Maxn][Maxn],match[Maxn],slack[Maxn],lx[Maxn],ly[Maxn];
bool visx[Maxn],visy[Maxn];
char st[Maxn][Maxn];
int N,M,n,m;
int abs(int x){
if (x<0) x=-x;return x;
}
int Dis(Node a,Node b){
return abs(a.x-b.x)+abs(a.y-b.y);
}
void init(){
memset(map,0,sizeof(map));
n=m=0;
for (int i=1;i<=N;i++){
scanf("%s",st[i]+1);st[i][0]='~';
for (int j=1;j<=M;j++){
if (st[i][j]=='m'){
n++;
g[n].x=i;g[n].y=j;
}
if (st[i][j]=='H'){
m++;
h[m].x=i;h[m].y=j;
}
}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
map[i][j]=-Dis(g[i],h[j]);
}
}
}
bool dfs(int i){
visx[i]=true;
for (int j=1;j<=m;j++){
int tmp=lx[i]+ly[j]-map[i][j];
if (visy[j]) continue;
if (tmp==0){
visy[j]=true;
if (match[j]==-1|| dfs(match[j])){
match[j]=i;
return true;
}
}
else if (tmp<slack[j]){
slack[j]=tmp;
}
}
return false;
}
int KM(){
memset(match,-1,sizeof(match));
//memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for (int i=1;i<=n;i++){
lx[i]=-INF;
for (int j=1;j<=m;j++){
if (lx[i]<map[i][j]) lx[i]=map[i][j];
}
}
for (int k=1;k<=n;k++){
for (int i=1;i<=n;i++) slack[i]=INF;
while(1){
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if (dfs(k)) break;
int dx=INF;
for (int i=1;i<=m;i++){
if (!visy[i]&&dx>slack[i]) dx=slack[i];
}
for (int i=1;i<=n;i++){
if (visx[i]) lx[i]-=dx;
}
for (int i=1;i<=m;i++){
if (visy[i]) ly[i]+=dx;
else slack[i]-=dx;
}
}
}
int ret=0;
for (int i=1;i<=m;i++)
ret+=map[match[i]][i];
return -ret;
}
int main(){
while (~scanf("%d%d",&N,&M),N||M){
init();
int ans=KM();
printf("%d\n",ans);
}
return 0;
}
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define Maxn 120
struct Node{
int x,y;
}g[Maxn],h[Maxn];
int map[Maxn][Maxn],match[Maxn],lx[Maxn],ly[Maxn];
bool visx[Maxn],visy[Maxn];
char st[Maxn][Maxn];
int N,M,n,m,slack;
int abs(int x){
if (x<0) x=-x;return x;
}
int Dis(Node a,Node b){
return abs(a.x-b.x)+abs(a.y-b.y);
}
void init(){
memset(map,0,sizeof(map));
n=m=0;
for (int i=1;i<=N;i++){
scanf("%s",st[i]+1);st[i][0]='~';
for (int j=1;j<=M;j++){
if (st[i][j]=='m'){
n++;
g[n].x=i;g[n].y=j;
}
if (st[i][j]=='H'){
m++;
h[m].x=i;h[m].y=j;
}
}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
map[i][j]=-Dis(g[i],h[j]);
}
}
}
bool dfs(int i){
visx[i]=true;
for (int j=1;j<=m;j++){
int tmp=lx[i]+ly[j]-map[i][j];
if (visy[j]) continue;
if (tmp==0){
visy[j]=true;
if (match[j]==-1|| dfs(match[j])){
match[j]=i;
return true;
}
}
else if (tmp<slack){
slack=tmp;
}
}
return false;
}
int KM(){
memset(match,-1,sizeof(match));
//memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for (int i=1;i<=n;i++){
lx[i]=-INF;
for (int j=1;j<=m;j++){
if (lx[i]<map[i][j]) lx[i]=map[i][j];
}
}
for (int k=1;k<=n;k++){
while(1){
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
slack=INF;
if (dfs(k)) break;
int dx=slack;
for (int i=1;i<=n;i++){
if (visx[i]) lx[i]-=dx;
if (visy[i]) ly[i]+=dx;
}
}
}
int ret=0;
for (int i=1;i<=m;i++)
ret+=map[match[i]][i];
return -ret;
}
int main(){
while (~scanf("%d%d",&N,&M),N||M){
init();
int ans=KM();
printf("%d\n",ans);
}
return 0;
}