hdu 1533 Going Home 最小费用最大流 入门题

Going Home

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 3125    Accepted Submission(s): 1590

Problem 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

题意:把H和m一一配对,他们所需走的最小步数和 为多少。

做法:用bfs 先找出 任意 H 和 m 直接的最小步数。记录下来。 然后像二分图一样建图。 起点到 所有home 流量1,费用0。 home 和man 之间的费用为距离,流量1,man和终点ee之间流量1,费用0。 建图完,然后用最小费用最大流 跑一边就ok了。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
#include <stdlib.h>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;

const int MAXN = 10100;
const int MAXM = 30000000;
const int INF = 0x3f3f3f3f;
struct Edge
{
	int to,next,cap,flow,cost;
}edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n)
{
	N = n;
	tol = 0;
	memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
	edge[tol].to = v;
	edge[tol].cap = cap;
	edge[tol].cost = cost;
	edge[tol].flow = 0;
	edge[tol].next = head[u];
	head[u] = tol++;
	edge[tol].to = u;
	edge[tol].cap = 0;
	edge[tol].cost = -cost;
	edge[tol].flow = 0;
	edge[tol].next = head[v];
	head[v] = tol++;
}
bool spfa(int s,int t)
{
	queue<int>q;
	for(int i = 0;i < N;i++)
	{
		dis[i] = INF;
		vis[i] = false;
		pre[i] = -1;
	}
	dis[s] = 0;
	vis[s] = true;
	q.push(s);
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		vis[u] = false;
		for(int i = head[u]; i != -1;i = edge[i].next)
		{
			int v = edge[i].to;
			if(edge[i].cap > edge[i].flow &&
				dis[v] > dis[u] + edge[i].cost )
			{
				dis[v] = dis[u] + edge[i].cost;
				pre[v] = i;
				if(!vis[v])
				{
					vis[v] = true;
					q.push(v);
				}
			}
		}
	}
	if(pre[t] == -1)return false;
	else return true;
}
//返回的是最大流, cost存的是最小费用
int minCostMaxflow(int s,int t,int &cost)
{
	int flow = 0;
	cost = 0;
	while(spfa(s,t))
	{
		int Min = INF;
		for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
		{
			if(Min > edge[i].cap - edge[i].flow)
				Min = edge[i].cap - edge[i].flow;
		}
		for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
		{
			edge[i].flow += Min;
			edge[i^1].flow -= Min;
			cost += edge[i].cost * Min;
		}
		flow += Min;
	}
	return flow;
} 

int n,m;
struct node
{
	int x,y,bu;
};
//addedge(int u,int v,int cap,int cost)
char mp[110][110];//地图
char num[110][110];//点查 号
int mp_dis[110][110];//号 号距离  前 home  后 men
int mp_vis[110][110];
int dir[4][2]={1,0,0,1,0,-1,-1,0};
void bfs(int x,int y)
{
	memset(mp_vis,-1,sizeof mp_vis);
	queue<node> q;
	node sta,nw,tem;
	sta.bu=0;
	sta.x=x;
	sta.y=y;
	q.push(sta);

	while(!q.empty())
	{
		nw=q.front();
		q.pop();
		if(mp[nw.x][nw.y]=='m')
			mp_dis[num[x][y]][num[nw.x][nw.y]]=nw.bu;
		for(int i=0;i<4;i++)
		{
			int xx=nw.x+dir[i][0];
			int yy=nw.y+dir[i][1];
			if(xx<0||xx>=n||yy<0||yy>=m)
				continue;
			if(mp_vis[xx][yy]!=-1&&nw.bu+1>=mp_vis[xx][yy])
				continue;
			tem.x=xx;
			tem.y=yy;
			mp_vis[xx][yy]=tem.bu=nw.bu+1;
			q.push(tem);
		}
	}
}

int main()
{
	while(cin>>n>>m,n||m)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%s",mp[i]);
		}
		int home,man;
		home=man=0;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(mp[i][j]=='H')
					num[i][j]=home++;
				if(mp[i][j]=='m')
					num[i][j]=man++;
			}
		}

		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(mp[i][j]=='H')
					bfs(i,j);

			}
		}
		int ss=home+man;
		int ee=home+man+1;
		init(home+man+2);

		for(int i=0;i<home;i++)
		{
			for(int j=0;j<man;j++)
			{
				addedge(i,home+j,1,mp_dis[i][j]);
			}
		}

		for(int i=0;i<home;i++)
			addedge(ss,i,1,0);
		for(int i=0;i<man;i++)
			addedge(home+i,ee,1,0);

		/*
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{

				printf("%c%d ",mp[i][j],num[i][j]);
			}
			puts("");
		}

		for(int i=0;i<home;i++)
		{
			for(int j=0;j<man;j++)
			{
				printf("%d ",mp_dis[i][j]);
			}
			puts("");
		}
		*/
		int ans;
		minCostMaxflow(ss,ee,ans);

		printf("%d\n",ans);

	}
	return 0;
}

/*
2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0
*/
时间: 2024-12-26 08:30:26

hdu 1533 Going Home 最小费用最大流 入门题的相关文章

hdu 1533 Going Home 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 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

POJ 2195 &amp; HDU 1533 Going Home(最小费用最大流)

题目链接: POJ:http://poj.org/problem?id=2195 HDU:http://acm.hdu.edu.cn/showproblem.php?pid=1533 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,

POJ2135 最小费用最大流模板题

练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include <cstring> #define MAXN 1005 #define MAXM 10005 #define INF 0x3f3f3f3f struct Edge { int y,c,w,ne;//c容量 w费用 }e[MAXM*4]; int n,m,x,y,w; int s,t,Maxflow

hdu 3488(KM算法||最小费用最大流)

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000

hdu 1853 Cyclic Tour 最小费用最大流

题意:一个有向图,现在问将图中的每一个点都划分到一个环中的最少代价(边权和). 思路:拆点,建二分图,跑最小费用最大流即可.若最大流为n,则说明是最大匹配为n,所有点都参与,每个点的入度和出度又是1,所以就是环. /********************************************************* file name: hdu1853.cpp author : kereo create time: 2015年02月16日 星期一 17时38分51秒 *******

HDU 1533--Going Home【最小费用最大流 &amp;&amp; 模板】

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3452    Accepted Submission(s): 1771 Problem Description On a grid map there are n little men and n houses. In each unit time, every

HDU ACM 4494 Teamwork 最小费用最大流

题意:n个工作地,m种工人,工作地0是仓库,其他的都需要修缮,每个地点需要多个工种的工人若干,不同工种不能相互取代.每个工作地有一个开工时间,凑齐所有工人后准时开工,修缮也需要一定时间.一个工人可以在一个地方工作完后再到其他地方,两地直接的距离是欧几里得距离,可以算作时间.最少需要多少工人. 分析:只用费用流.每种工人不能相互替换,没有任何关系.因此对每个工种进行建图求解最小费用累加即可得到最终结果. 超级源点cs是仓库,超级汇点为ct. 一个地点拆成三个点,i.i'.i".k表示工种,对每个点

hdu 4067 Random Maze 最小费用最大流

题意: 给出n个点,m条边,入口s和出口t,对于每条边有两个值a,b,如果保留这条边需要花费:否则,移除这条边需要花费b. 题目要求用最小费用构造一个有向图满足以下条件: 1.只有一个入口和出口 2.所有路都是唯一方向 3.对于入口s,它的出度 = 它的入度 + 1 4.对于出口t,它的入度 = 它的出度 + 1 5.除了s和t外,其他点的入度 = 其出度 最后如果可以构造,输出最小费用:否则输出impossible. 思路: 表示建图太神..给个博客链接:http://www.cppblog.

【网络流#2】hdu 1533 最小费用最大流模板题

嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边 按照这个图跑一发费用流即可 把代码挂上去,用的是前向星写的 1 #include<cstdio> 2 #include<cstr