题意:给一张地图,标记num个人和房子的位置,每个房子只能住一个人,求所有人都进入房子至少需要多少步
解析:首先计算出每一个人到每一个房子的距离,然后就是套用KM求最佳匹配的板子。不过KM算法不好理解,这里借用一位大佬的博客:博客链接 。大佬写的十分生动,方便理解。
以下为AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
char mp[101][101];
struct Node
{
int x,y;
}house[101],man[101];
int num;
int dis[101][101];
//A,B为顶标,在算法执行最后,所有满足A[i]+B[j]=dis[i][j]的边构成的子图有完全匹配(最大权匹配)
int A[101]; //初始为所有与定点i关联的边的最大权(A,B看成入住期望值)
int B[101]; //初始为0
bool vis_man[101],vis_house[101]; //记录每一轮匹配过的人和房子
int match[101]; //记录每个房子的主人
int lack[101]; //记录离房子被看中还差多少期望
bool dfs(int i)
{
vis_man[i]=true;
for(int j=0;j<num;j++)
{
if(vis_house[j]) //房子这一轮已经有人住了
continue;
int t=A[i]+B[j]-dis[i][j];
if(t==0) //如果房子被相中了
{
vis_house[j]=true;
if(match[j]==-1||dfs(match[j])) //房子每人住或者住这个房子的人可以住其他房子
{
match[j]=i; //i入住j
return true;
}
}
else
lack[j]=min(lack[j],t);
}
return false;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(B,0,sizeof(B));
for(int i=0;i<num;i++)
{
dis[i][0]=abs(man[i].x-house[0].x)+abs(man[i].y-house[0].y);
dis[i][0]=-dis[i][0];
A[i]=dis[i][0];
for(int j=1;j<num;j++)
{
dis[i][j]=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y);
dis[i][j]=-dis[i][j]; //因为KM算法求的是最大费,所以这里全部取反
A[i]=max(A[i],dis[i][j]);
}
}
for(int i=0;i<num;i++)
{
memset(lack,inf,sizeof(lack));
while(1)
{
memset(vis_man,false,sizeof(vis_man));
memset(vis_house,false,sizeof(vis_house));
if(dfs(i)) //相中房子了
break;
int d=inf; //如果没有相中,人对房子期望减小
for(int j=0;j<num;j++)
if(!vis_house[j])
d=min(d,lack[j]); //寻找可以减的最大的数
for(int j=0;j<num;j++) //所有没有相中房子的人的期望减小
{
if(vis_man[j])
A[j]-=d;
if(vis_house[j]) //所有被看过的房子的期望值增加
B[j]+=d;
else //因为人们期望减小,没有访问过的房子离被人看中又进了一步
lack[j]-=d;
}
}
}
int sum=0;
for(int i=0;i<num;i++)
sum+=dis[match[i]][i];
return sum;
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m)&&(n!=0&&m!=0))
{
for(int i=0;i<n;i++)
scanf("%s",mp[i]);
int n1=0,n2=0; //记录人数和房子数
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(mp[i][j]=='m')
{
man[n1].x=i;
man[n1].y=j;
n1++;
}
else if(mp[i][j]=='H')
{
house[n2].x=i;
house[n2].y=j;
n2++;
}
}
num=n1;
printf("%d\n",-KM());
}
return 0;
}