题意:n*m的地图有人和房子,要让每个人进入一个房子(每个房子只能进入一个人,人可以走任何地方(可以经过房子也可以多
人在一个位置,每个人走一步花费1美元,求最小的花费。
思路:最小费用流模板,建好图。。抄模板就行了,这个图比较好建。
原点0~(1~k)房子~(k+1~k+kk)人~(k+kk+1)结点
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define N 100000
#define INF 0x3fffffff
using namespace std;
char mp[106][106];
typedef pair<int ,int >P;
struct edge
{
int to,cap,cost,rev;
};
int V;
vector <edge> G[N];
int h[N];
int dist[N];
int prevv[N],preve[N];
void add(int from,int to,int cap,int cost)
{
G[from].push_back((edge){to,cap,cost,G[to].size()});
G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
int min_cost_flow(int s,int t,int f)
{
int res=0;
fill(h,h+V,0);
while(f>0)
{
priority_queue<P,vector<P>, greater<P> > que;
fill(dist,dist+V,INF);
dist[s]=0;
que.push(P(0,s));
while(!que.empty())
{
P p=que.top();que.pop();
int v=p.second;
if(dist[v]<p.first) continue;
for(int i=0;i<G[v].size();i++)
{
edge &e=G[v][i];
if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])
{
dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
prevv[e.to]=v;
preve[e.to]=i;
que.push(P(dist[e.to],e.to));
}
}
}
if(dist[t]==INF)
{
return -1;
}
for(int v=0;v<V;v++)
h[v]+=dist[v];
int d=f;
for(int v=t;v!=s;v=prevv[v])
{
d=min(d,G[prevv[v]][preve[v]].cap);
}
f-=d;
res+=d*h[t];
for(int v=t;v!=s;v=prevv[v])
{
edge &e=G[prevv[v]][preve[v]];
e.cap-=d;
G[v][e.rev].cap+=d;
}
}
return res;
}
struct nomd
{
int x,y;
}w[100000];
nomd ww[100000];
int ta(int a,int b)
{
return fabs(w[a].x-ww[b].x)+abs(w[a].y-ww[b].y);
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m))
{
memset(mp,0,sizeof(mp));
if(n==0&&m==0)
break;
for(int i=0;i<n;i++)
scanf("%s",mp[i]);
int k=0,kk=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]=='H')
{
w[++k].x=i;w[k].y=j;
add(0,k,1,0);
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]=='m')
{
ww[++kk].x=i,ww[kk].y=j;
}
}
}
for(int i=1;i<=kk;i++)
{
add(k+i,k+kk+1,1,0);
}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=kk;j++)
{
add(i,k+j,1,ta(i,j));
}
}
V=k+kk+1+1;
printf("%d\n",min_cost_flow(0,k+kk+1,kk));
for(int i=0;i<=k+kk+1;i++)
G[i].clear();
memset(w,0,sizeof(w));
memset(ww,0,sizeof(ww));
memset(prevv,0,sizeof prevv);
memset(preve,0,sizeof(preve));
}
return 0;
}