Bipartitegraph2195

题目大意:图中有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;

}

时间: 2024-10-07 16:08:09

Bipartitegraph2195的相关文章