POJ 2195 - Going Home - [最小费用最大流][MCMF模板]

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

Time Limit: 1000MS Memory Limit: 65536K

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
转载请注明出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6732762

大致题意:
给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。

构图:
把man作为一个顶点集合U,house作为另一个顶点集合V,把U中所有点到V中所有点addedge{from∈U,to∈V,cap=1,cost=两点间哈密顿距离},构成一个多源多汇的二分图。
构造一个超级源点s和超级汇点t:s与U中所有点相连,费用为0,容量为1;V中所有点与t相连,费用为0,容量为1。

这种构图思路很简单,我们建立起的二分图:

不难想象,maxflow必然等于the number of men(or the number of houses),在上图的例子中,即为3;

由于我们在所有man点与house点间建立的边容量为1,显然,最大流保证了:

  ①所有man都能到house里;

  ②一个man只进到一间house,一间house只有一个man;

就像在上图中,最大流的情况下,每个m[i]只能选一个H[j],而且i,j也不能重复;

这恰好就满足了题目所给的要求,然后,只要我们在m[i]到H[j]的边上加上cost=Hamiltonian_distance(m[i],H[j]),求出最小费用就是答案啦。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<vector>
  5 #include<queue>
  6 #define MAXN 203
  7 #define INF 0x3f3f3f3f
  8 using namespace std;
  9 struct Edge{
 10     int u,v,c,f,a;
 11 };
 12 struct MCMF
 13 {
 14     int s,t;
 15     vector<Edge> E;
 16     vector<int> G[MAXN];
 17     int vis[MAXN];
 18     int d[MAXN];
 19     int pre[MAXN];
 20     int aug[MAXN];
 21     void init(int l,int r)
 22     {
 23         for(int i=l;i<=r;i++) G[i].clear();
 24         E.clear();
 25     }
 26     void addedge(int from,int to,int cap,int cost)
 27     {
 28         E.push_back((Edge){from,to,cap,0,cost});
 29         E.push_back((Edge){to,from,0,0,-cost});
 30         int m=E.size();
 31         G[from].push_back(m-2);
 32         G[to].push_back(m-1);
 33     }
 34     bool SPFA(int s,int t,int &flow,int &cost)
 35     {
 36         memset(d,INF,sizeof(d));
 37         memset(vis,0,sizeof(vis));
 38         d[s]=0, vis[s]=1, pre[s]=0, aug[s]=INF;
 39         queue<int> q;
 40         q.push(s);
 41         while(!q.empty())
 42         {
 43             int now=q.front(); q.pop();
 44             vis[now]=0;
 45             for(int i=0;i<G[now].size();i++)
 46             {
 47                 Edge& e=E[G[now][i]];
 48                 int nex=e.v;
 49                 if(e.c>e.f && d[nex]>d[now]+e.a)
 50                 {
 51                     d[nex]=d[now]+e.a;
 52                     pre[nex]=G[now][i];
 53                     aug[nex]=min(aug[now],e.c-e.f);
 54                     if(!vis[nex])
 55                     {
 56                         q.push(nex);
 57                         vis[nex]=1;
 58                     }
 59                 }
 60             }
 61         }
 62         if(d[t]==INF) return 0;
 63         flow+=aug[t];
 64         cost+=d[t]*aug[t];
 65         for(int i=t;i!=s;i=E[pre[i]].u)
 66         {
 67             E[pre[i]].f+=aug[t];
 68             E[pre[i]^1].f-=aug[t];
 69         }
 70         return 1;
 71     }
 72
 73     int mincost()
 74     {
 75         int flow=0,cost=0;
 76         while(SPFA(s,t,flow,cost));
 77         return cost;
 78     }
 79 }mcmf;
 80
 81 char map[103][103];
 82 struct Node{int row,col;};
 83 int Hami_dist(Node a,Node b){return abs(a.row-b.row) + abs(a.col-b.col);}
 84
 85 int main()
 86 {
 87     int N,M;//N行,M列
 88     while(scanf("%d%d",&N,&M) && N!=0)
 89     {
 90         vector<Node> men,houses;
 91         for(int i=1;i<=N;i++) scanf("%s",map[i]+1);
 92         for(int i=1;i<=N;i++)
 93         {
 94             for(int j=1;j<=M;j++)
 95             {
 96                 if(map[i][j]==‘m‘) men.push_back((Node){i,j});
 97                 if(map[i][j]==‘H‘) houses.push_back((Node){i,j});
 98             }
 99         }
100         int n=men.size();
101         mcmf.init(0,2*n+1);
102         mcmf.s=0, mcmf.t=2*n+1;
103         for(int i=0;i<n;i++)
104         {
105             mcmf.addedge(mcmf.s,i+1,1,0);
106             for(int j=0;j<n;j++)
107             {
108                 if(i==0) mcmf.addedge(j+1+n,mcmf.t,1,0);
109                 mcmf.addedge(i+1,j+1+n,1,Hami_dist(men[i],houses[j]));
110             }
111         }
112         printf("%d\n",mcmf.mincost());
113     }
114 } 
时间: 2024-08-15 11:53:57

POJ 2195 - Going Home - [最小费用最大流][MCMF模板]的相关文章

POJ 2195 Going Home (最小费用最大流)

题目链接:http://poj.org/problem?id=2195 题意:n*m的矩阵,地图上有若干个人(m)和房子(H),且人与房子的数量一致.man每移动一格费用为1,一个房子只能住一个人.现在要求所有的人出发,都入住房子,求最少话费. 思路:建立一个超级源点和汇点,源点与人相连费用为0,容量为1,人与房子相连,费用为人与房子的距离,容量为1,房子与汇点相连,费用为0,容量为1 #include <iostream> #include <cstdlib> #include

POJ 2195 地图的最小费用最大流

思路:这题刚开始看就知道是最小费用最大流了,因为求出最优嘛,而且要m,H要一一对应,所以不是二分图匹配就是最小费用最大流. 不过,刚开始还在想每个m与H之间的最小花费如何求,难道要用dfs搜索吗?这样想之后看了下题目给的时间是1000ms,然后就把dfs搜索m与H之间的最短距离排除了.然后想了想,其实尼玛太简单了,因为题目说了只能垂直与竖直的走,所以最短距离不就是两个横坐标相减与两个纵坐标相减之和嘛! 然后每对m与H之间都连边,流量为1(因为每对匹配不能重复),费用为它们之间的距离即花费:然后建

POJ 2195 Going Home 最小费用最大流 尼玛,心累

D - Going Home Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2195 Appoint description: Description On a grid map there are n little men and n houses. In each unit time, every little man can mo

POJ 2516 Minimum Cost(最小费用最大流,坑题)

题目链接:http://poj.org/problem?id=2516 题意:有N个店,M个供货商,K种商品.已知供货商的仓库里每种商品的数量以及每种商品运送到每个店的费用,每个店铺对各种商品的需求数量,求最少话费. Input  第一行:N,M,K. 然后1 - N行,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件. 然后 N+1 - M行  ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件. 然后是K个矩阵  ,每个N行M列,第ji个矩阵的第i行第j

POJ 2516 Minimum Cost (最小费用最大流)

Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K       Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy

poj2135最小费用最大流经典模板题

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13509   Accepted: 5125 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

最小费用最大流基础模板(洛谷3381)

如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向P3381 [模板]最小费用最大流边的个数.源点序号.汇点序号. 接下来M行每行包含四个正整数ui.vi.wi.fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi. 输出格式: 一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用. 输入样例#1:

POJ 3680: Intervals【最小费用最大流】

题目大意:你有N个开区间,每个区间有个重量wi,你要选择一些区间,使得满足:每个点被不超过K个区间覆盖的前提下,重量最大 思路:感觉是很好想的费用流,把每个区间首尾相连,费用为该区间的重量的相反数(由于要最大,所以是求最大费用最大流),容量为1,至于不超过K的限制,只要从源点到第一个点的流量为K就行,剩下每个相邻的点相连,费用为0,流量只要大于的等于K就可以(我取的正无穷) //poj3680 #include <stdio.h> #include <iostream> #incl

HDU 1533 最小费用最大流(模板)

http://acm.hdu.edu.cn/showproblem.php?pid=1533 这道题直接用了模板 题意:要构建一个二分图,家对应人,连线的权值就是最短距离,求最小费用 要注意void init(int n) 这个函数一定要写 一开始忘记写这个WA了好几发 还有这个题很容易T掉,赋值建图要简化,一开始构建成网络流那种图一直T #include <stdio.h> #include <string.h> #include <iostream> #includ