POJ-2195-Going Home(最小费用最大流,MCMF,向前星建图,边点回溯)

题目链接:http://poj.org/problem?id=2195

Description

On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man. 

Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point. 


You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.

Input

There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.

Output

For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.

Sample Input

2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0

Sample Output

2
10
28

题目大意:多组输入,0,0结束;

对于每组样例,输入n,m表示n*m的地图,之后是这个地图,地图上的m表示人,H表示房子,一个人只能住一个房子,一个房子只能住一个人,求出所有人都住到房子中的人们走的最小步数;

输出最小步数,很明显,源 - 人 - 房子 - 汇 ,流量限制为1,花费只有 人 - 房子 是曼哈顿距离,其他的都是0;

因此直接建图,1A

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);
struct dots{
	int x,y;
}dots[110],dott[110];
struct node{
	int v,w,cost,nxt;
	node(int _v=0,int _w=0,int _cost=0,int _nxt=0):
    v(_v),w(_w),cost(_cost),nxt(_nxt){}
}edge[100010<<1];
int head[100010],ecnt;
int dis[100010],flow[100010],pre[100010],last[100010];
//	最小花费	流量			前驱		这条边 
int vis[100010];
int maxw,mincost;
int n,m,s,t;
void intt()
{
	clean(head,-1);
	clean(last,0);
	clean(pre,0);
	ecnt=0;
	maxw=0,mincost=0;
}
void add(int u,int v,int w,int cost)
{
	edge[ecnt]=node(v,w,cost,head[u]);
	head[u]=ecnt++;
	edge[ecnt]=node(u,0,-cost,head[v]);
	head[v]=ecnt++;
}
/*---上面的是板子,不用动---*/

bool spfa()
{
	clean(dis,INF);
	clean(flow,INF);
	clean(vis,0);
	queue<int> que;
	que.push(s);
	vis[s]=1;
	dis[s]=0;
	pre[t]=-1;
	while(que.size())
	{
		int u=que.front();
		que.pop();
		vis[u]=0;
		for(int i=head[u];i+1;i=edge[i].nxt)
		{
			int temp=edge[i].v;
			if(edge[i].w>0&&dis[temp]>dis[u]+edge[i].cost)
			{
				dis[temp]=dis[u]+edge[i].cost;
				pre[temp]=u;
				last[temp]=i;
				flow[temp]=min(flow[u],edge[i].w);
				if(vis[temp]==0)
				{
					vis[temp]=1;
					que.push(temp);
				}
			}
		}
	}
	return pre[t]!=-1;
}

void MCMF()
{
	while(spfa())
	{
		int u=t;
		//cout<<flow[t]<<" "<<dis[t]<<endl;
		//cout<<maxw<<" "<<mincost<<" --> ";
		maxw+=flow[t];
		mincost+=dis[t];
		//cout<<maxw<<" "<<mincost<<endl;
		while(u!=s)
		{
			edge[last[u]].w-=flow[t];
			edge[last[u]^1].w+=flow[t];
			u=pre[u];
		}
	}
	cout<<mincost<<endl;
}

int main()
{
	std::ios::sync_with_stdio(false);
	while(cin>>n>>m&&n!=0)
	{
		intt();
		s=0,t=10001;
		int si=0,ti=0;
		string str;
		for(int i=1;i<=n;++i)
		{
			cin>>str;
			for(int j=0;j<m;++j)
			{
				if(str[j]=='m')
					dots[si].x=i,dots[si++].y=j+1;
				if(str[j]=='H')
					dott[ti].x=i,dott[ti++].y=j+1;
			}
		}
		for(int i=0;i<si;++i)
		{
			add(0,i+1,1,0);//源 - 人 
			for(int j=0;j<ti;++j)// 人 - 屋 
				add(i+1,100+j+1,1,abs(dots[i].x-dott[j].x)+abs(dots[i].y-dott[j].y));
		}
		for(int i=0;i<ti;++i)//屋 - 汇
			add(i+100+1,t,1,0);
//		for(int i=s;i<=t;++i)
//		{
//			cout<<i<<" : ";
//			for(int j=head[i];j+1;j=edge[j].nxt)
//				cout<<edge[j].v<<" "<<edge[j].w<<" "<<edge[j].cost<<" -->> ";
//			cout<<endl;
//		}
		MCMF();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81984738