POJ 2195 Going Home(KM算法模板)

时间:2022-12-03 12:10:48

题目链接: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+;
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=;y<ny;y++){
if(visy[y]) continue;
int tmp=lx[x]+ly[y]-g[x][y];
if(tmp==){
visy[y]=true;
if(link[y]==-||dfs(link[y])){
link[y]=x;
return true;
}
}
else if(slack[y]>tmp)
slack[y]=tmp;
}
return false;
} int KM(){
memset(link,-,sizeof(link));
memset(ly,,sizeof(ly));
for(int i=;i<nx;i++){
lx[i]=-INF;
for(int j=;j<ny;j++){
if(g[i][j]>lx[i])
lx[i]=g[i][j];
}
}
for(int x=;x<nx;x++){
for(int i=;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=;i<ny;i++){
if(!visy[i]&&slack[i]<d)
d=slack[i];
}
for(int i=;i<nx;i++){
if(visx[i])
lx[i]-=d;
}
for(int i=;i<ny;i++){
if(visy[i])
ly[i]+=d;
}
}
}
int ans=;
for(int i=;i<ny;i++){
if(link[i]!=-)
ans+=g[link[i]][i];
}
return ans;
} int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==&&m==) break;
nx=ny=;
char str[N];
for(int i=;i<n;i++){
scanf("%s",str);
for(int j=;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=;i<nx;i++){
for(int j=;j<ny;j++){
g[i][j]=-(abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y));
}
}
printf("%d\n",-KM());
}
return ;
}