https://vjudge.net/contest/243107#problem/D
题目的意思是有一些人和相同数量的房子,每一个人都要到一所房子里去,每一个人走一步需要花费一元,求最小花费
最小花费=最大流
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<map>
#define inf 0x3f3f3f3f
using namespace std;
int n,m,M,H;
char a[110][110];//存图
int g[300][300];
int cost[300][300];//花费
int dis[300];//最小费用
int vis[300];
int pre[300];
struct node
{
int x,y;
} b[150],c[150];
int bfs(int s,int t)
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
memset(dis,inf,sizeof(dis));
vis[s]=1;
dis[s]=0;
pre[s]=s;
queue<int>q;
q.push(s);
while(!q.empty())
{
int f=q.front();
q.pop();
vis[f]=0;//spfa算法求
for(int i=0; i<=t; i++)
{
if(g[f][i]&&dis[i]>dis[f]+cost[f][i])//求最小花费
{
dis[i]=dis[f]+cost[f][i];
pre[i]=f;
if(vis[i]==0)
{
vis[i]=1;
q.push(i);
}
}
}
}
if(pre[t]==-1)
return 0;
return 1;
}
int EK(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
for(int i=t; i!=s; i=pre[i])
{
g[pre[i]][i]-=1;
g[i][pre[i]]+=1;
}
ans+=dis[t];
}
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
M=0,H=0;
for(int i=1; i<=n; i++)
{
scanf("%s",a[i]+1);
for(int j=1; j<=m; j++)
{
if(a[i][j]=='m')
{
M++;
b[M].x=i;
b[M].y=j;
}
if(a[i][j]=='H')
{
H++;
c[H].x=i;
c[H].y=j;
}
}
}
memset(g,0,sizeof(g));
memset(cost,0,sizeof(cost));
for(int i=1; i<=M; i++)//求花费
{
for(int j=1; j<=H; j++)
{
int tmp=abs(b[i].x-c[j].x)+abs(b[i].y-c[j].y);
cost[i][M+j]=tmp;
cost[M+j][i]=-tmp;
g[i][M+j]=inf;//人到房子为无穷
}
}
for(int i=1; i<=M; i++)//到源点和汇点为1(一所房子只能去一个人)
{
g[0][i]=1;
g[M+i][M+H+1]=1;
}
printf("%d\n",EK(0,M+H+1));
}
}