hdu 1533 going home (最小费用最大流)
思路: 在一个n*m的矩形区域,有多个房子和多个人,问一个人选一个房子,一个人走到房子的花费为人和房子之间的曼哈顿距离,问所有人都走到房子里,总花费最小是多少?
题解:经典的MCMF,建图:虚拟一个源点source,和一个汇点sink,source指向所有人,每条边的权值为1,
每个房子都指向汇点,权值为1,对于一个人,和每个房子都有一条边,权值为1。
注意:还有一个花费数组,cost[][],记录人和房子间的距离,注意要和流量图一样建立反向边!原因如下图:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define M 205
#define N 102
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
#define FOR(i,a,n) for(int i=(a);i<=(n);++i)
int cap[M][M],cost[M][M];
int father[M],d[M];
bool vis[M];
int sourse,sink;
void spfa()
{
queue<int> Q;
CLS(vis,0);
CLS(father,-1);
for(int i=sourse;i<=sink;i++)d[i]=INF;
d[sourse]=0;
Q.push(sourse);
int pre;
while(!Q.empty())
{
pre=Q.front();
Q.pop();
vis[pre]=0;
for(int i=sourse;i<=sink;i++)
if(cap[pre][i]&&d[i]>d[pre]+cost[pre][i])
{
d[i]=d[pre]+cost[pre][i];
father[i]=pre;
if(!vis[i])
{
vis[i]=1;
Q.push(i);
}
}
}
}
void MCMF()
{
int mincost=0;
while(1)
{
spfa();
if(father[sink]==-1)break;//汇点不可达
for(int i=sink;i!=sourse;i=father[i])
{
cap[father[i]][i]-=1;
cap[i][father[i]]+=1;
}
mincost+=d[sink];
}
printf("%d\n",mincost);
}
struct position
{
int x,y;
} man[N],house[N];
int main()
{
char s[N];
int n,m;
int a,b;
while(~scanf("%d%d",&n,&m)&&(n||m))
{
a=b=0;
CLS(cap,0);
CLS(cost,0);
for(int i=0; i<n; i++)
{
scanf("%s",s);
for(int j=0; j<m; j++)
{
if(s[j]=='m')
man[++a].x=i,man[a].y=j;
if(s[j]=='H')
house[++b].x=i,house[b].y=j;
}
}
//构图
sourse=0;sink=a+b+1;
for(int i=1; i<=a; i++)
{
cap[0][i]=1;
for(int j=1; j<=b; j++)
{
cap[i][a+j]=1;
cost[i][a+j]=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y);
cost[a+j][i]=-cost[i][a+j];
}
}
for(int i=a+1; i<sink; i++)
cap[i][sink]=1;
MCMF();
}
return 0;
}