题目描述:
给一个矩阵,m表示人,h表示房子。.表示空地。人和房子数相等。求让所有的人进入不同的房子内,问最少走多少步?
解题思路:
KM算法——求最佳匹配的。该题求最佳匹配 = 权值最小匹配。构图——二分图,把人道房子距离乘以-1,就转变为求最大权值匹配。两个函数:一个求完备匹配的匈牙利函数,一个更新可行顶标-执行求完备匹配的函数。(注意写的时候要细心。。一个条件忘了改wa了大半天)
代码:
#include <stdio.h>
#include <stdlib.h>
#define N 202
typedef struct{
int x;
int y;
}Pos;
int map[N][N], m_cnt, h_cnt, n, M;
char input[N][N];
Pos m[N], H[N];
int lx[N], ly[N], sx[N], sy[N], visit[N], link[N];
int dfs(int v){
int i;
sx[v] = 1;
for(i=1;i<=h_cnt;i++){
if(!sy[i] && lx[v] + ly[i] == map[v][i]){
sy[i] = 1;
if(link[i] == -1 || dfs(link[i])){
link[i] = v;
return 1;
}
}
}
return 0;
}
int km(){
int i,j,k,min,sum;
for(i=1;i<=m_cnt;i++){
lx[i] = -40004;
ly[i] = 0;
for(j=1;j<=h_cnt;j++)
if(lx[i] < map[i][j])
lx[i] = map[i][j];
link[i] = -1;
}
for(i=1;i<=h_cnt;i++){
while(1){
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
if(dfs(i))
break;
//update
min = 10000;
for(j=1;j<=m_cnt;j++)
if(sx[j])
for(k=1;k<=h_cnt;k++)
if(!sy[k])
if( lx[j] + ly[k] - map[j][k] < min)
min = lx[j] + ly[k] - map[j][k];
for(j=1;j<=m_cnt;j++){
if(sx[j])
lx[j] -= min;
}
for(j=1;j<=h_cnt;j++){
if(sy[j])
ly[j] += min;
}
}
}
sum = 0;
for(j=1;j<=h_cnt;j++){
if(link[j]!=-1)
sum += map[link[j]][j]; //lx[j] + ly[j]
}
return sum;
}
main(){
int i,j;
scanf("%d %d",&n, &M);
while(n!=0){
m_cnt = 0;
h_cnt = 0;
for(i=1;i<=n;i++){
scanf("%s",input[i]);
for(j=0;j<M;j++){
if(input[i][j] == 'm'){
m_cnt ++;
m[m_cnt].x = i;
m[m_cnt].y = j;
}
else if(input[i][j]=="H"){
h_cnt ++;
H[h_cnt].x = i;
H[h_cnt].y = j;
}
}
}
//构建二分图
for(i=1;i<=m_cnt;i++)
for(j=1;j<=h_cnt;j++){
map[i][j] = -1*(abs(m[i].x - H[j].x)+abs(m[i].y - H[j].y));
}
printf("%d\n",-1*km());
scanf("%d %d",&n, &M);
}
system("pause");
return 0;
}