题意:给你一个图,H表示房子,m表示人,为你这些人进到房子的最小话费是多少。
直接把源点和人建边,人和房子建边,房子和汇点建边。
跑一边最小费用最大流就好。
AC代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
const int MM=1e5;
const int inf=1<<30;
struct MCMF{
struct Edge{
int from,to,cap,flow,cost,next;
Edge(){}
Edge(int from,int to,int cap,int flow,int cost,int next){
this->from=from;
this->to=to;
this->cap=cap;
this->flow=flow;
this->cost=cost;
this->next=next;
}
}ed[666666];
int n,m,s,t,head,tail,lnum;
int vis[MM],dis[MM],pre[MM];//pre 上一条弧
int cag[MM],que[MM*3],start[MM];//cag 可改进量
void init(){
lnum=0;
rep(i,s,t) start[i]=-1;
}
void add(int x,int y,int v,int c){
ed[lnum]=Edge(x,y,v,0,c,start[x]);
start[x]=lnum++;
ed[lnum]=Edge(y,x,0,0,-c,start[y]);
start[y]=lnum++;
}
bool spfa(int& flow,int& cost){
rep(i,s,t) dis[i]=inf,vis[i]=0;
head=tail=0;
dis[s]=0;vis[s]=1;pre[s]=0;cag[s]=inf;
que[tail++]=s;
while(head<tail){
int x=que[head++];
vis[x]=0;
for(int i=start[x];~i;i=ed[i].next){
Edge& e=ed[i];
if(e.cap>e.flow&&dis[e.to]>dis[x]+e.cost){
dis[e.to]=dis[x]+e.cost;
pre[e.to]=i;
cag[e.to]=min(cag[x],e.cap-e.flow);
if(!vis[e.to]){
que[tail++]=e.to;
vis[e.to]=1;
}
}
}
}
if(dis[t]==inf) return false;
flow+=cag[t];
cost+=dis[t]*cag[t];
int x=t;
while(x!=s){
ed[pre[x]].flow+=cag[t];
ed[pre[x]^1].flow-=cag[t];
x=ed[pre[x]].from;
}
return true;
}
int Mincost(){
int flow=0,cost=0;
while((spfa(flow,cost)));
return cost;
}
}mc;
struct node{
int x,y,idx;
};
node hou[MM],man[MM];
int toth,totm;
int main()
{
char mp[100][100];
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0 && m==0 ) break;
mc.init();
toth = totm = 0;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
mc.s=0;mc.t=n*m+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
{
if(mp[i][j]=='m')
{
man[totm].idx=(i-1)*m+j;
man[totm].x=i;
man[totm++].y=j;
}
else if(mp[i][j]=='H')
{
hou[toth].idx=(i-1)*m+j;
hou[toth].x=i;
hou[toth++].y=j;
}
}
}
for(int i=0;i<totm;i++){
mc.add(0,man[i].idx,1,0);
}
for(int i=0;i<toth;i++){
mc.add(hou[i].idx,mc.t,1,0);
}
for(int i=0;i<totm;i++){
for(int j=0;j<toth;j++){
int d=abs(man[i].x-hou[j].x)+abs(man[i].y-hou[j].y);
mc.add(man[i].idx,hou[j].idx,1,d);
}
}
cout<<mc.Mincost()<<endl;
}
}