题目大意:图中有n个man和n个home,并且一个人只能住在一个房子里面,房子和人的个数是相等的。并且每个人移动一步的代价是1,怎么使
所有人住在房子里,并且使所有人的代价和最小。
给出一个n×m的图,m表示人,H表示房子,.表示空地,当然房子不算障碍物,可以穿过
方法用最大流最小费 或者最佳二分匹配KM算法
最大流最小费
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
#define oo 2000000000
using namespace std;
struct node1
{
int y,x;
}man[105],house[105];
struct node2
{
int f,w;
}s[205][205];
struct node3
{
int pre,w;
}dp[205];
int n,m,NumMan,NumHouse,ans;
char arc[105][105];
bool used[205],inqueue[205];
queue<int> myqueue;
bool SPFA()
{
int h,k,i;
while (!myqueue.empty()) myqueue.pop();
memset(dp,-1,sizeof(dp));
memset(inqueue,false,sizeof(inqueue));
myqueue.push(0); dp[0].w=0;
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
inqueue[h]=false;
for (i=0;i<=n;i++)
if (s[h][i].f && (dp[i].pre==-1 || dp[i].w>dp[h].w+s[h][i].w))
{
dp[i].w=dp[h].w+s[h][i].w;
dp[i].pre=h;
if (!inqueue[i])
{
inqueue[i]=true;
myqueue.push(i);
}
}
}
if (dp[n].pre==-1) return false;
return true;
}
void MinCostOfMaxFlow()
{
int i,m,way[205],Flow;
ans=0;
while (SPFA())
{
m=0;
i=n;
memset(way,0,sizeof(way));
while (1)
{
way[++m]=i;
if (!i) break;
i=dp[i].pre;
}
Flow=oo;
for (i=1;i<m;i++)
if (s[way[i+1]][way[i]].f<Flow) Flow=s[way[i+1]][way[i]].f;
for (i=1;i<m;i++)
{
ans+=s[way[i+1]][way[i]].w*Flow;
s[way[i+1]][way[i]].f-=Flow;
s[way[i]][way[i+1]].f+=Flow;
// s[way[i]][way[i+1]].w=-s[way[i+1]][way[i]].w;//这一句没必要,前面赋值过了 就不用了
}
}
}
int absI(int x)
{
if (x<0) return -x;
return x;
}
int main()
{
// freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int i,j;
while (~scanf("%d%d\n",&n,&m))
{
if (!n && !m) break;
for (i=1;i<=n;i++) gets(arc[i]+1); //从arc[i][1]开始,而不是arc[i][0]
NumMan=NumHouse=0;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (arc[i][j]==‘m‘)
{
NumMan++;
man[NumMan].y=i;
man[NumMan].x=j;
}else
if (arc[i][j]==‘H‘)
{
NumHouse++;
house[NumHouse].y=i;
house[NumHouse].x=j;
}
memset(s,0,sizeof(s));
for (i=1;i<=NumMan;i++)
for (j=1;j<=NumHouse;j++)
{
s[i][j+NumMan].f=1; //MAN节点和HOUSE节点分开,防止在一维数组里面出现重合。流量总值为1,因为一个人最多只能去一个房间
s[i][j+NumMan].w=absI(man[i].x-house[j].x)+absI(man[i].y-house[j].y);
s[j+NumMan][i].w=-s[i][j+NumMan].w;//这一句还是要加上。
}
for (i=1;i<=NumMan;i++)//超级源点到人的代价是1,总流量是人的总流量,为1
{
s[0][i].f=1;
s[0][i].w=0;
}
for (i=1;i<=NumHouse;i++)//每个房子最多住一个人
{
s[i+NumHouse][NumMan+NumHouse+1].f=1;
s[i+NumHouse][NumMan+NumHouse+1].w=0;
}
n=NumMan+NumHouse+1;
MinCostOfMaxFlow();
printf("%d\n",ans);
}
return 0;
}