POJ 2195 一人一房 最小费用流 建图 水题

Going Home

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 21010   Accepted: 10614

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

Source

Pacific Northwest 2004

题意:

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

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
#define MM(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ULL;
const int mod = 1000000007;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
const int big=50000;
int max(int a,int b) {return a>b?a:b;};
int min(int a,int b) {return a<b?a:b;};
const int N = 70;
const int M=10000+100;
struct edge{
   int to,cap,cost,rev;
};

vector<edge> G[1005];
int dist[1005],inq[1005],prev[1005],prel[1005];
struct Point{
   int x,y;
};

int n,m,x,y,c,cnth,cntm;
Point house[105],men[105];

void add_edge(int u,int v,int cap,int cost)
{
    G[u].push_back(edge{v,cap,cost,G[v].size()});
    G[v].push_back(edge{u,0,-cost,G[u].size()-1});
}

int mincost(int s,int t,int f)
{
    int ans=0;
    while(f>0)
    {
      memset(dist,inf,sizeof(dist));
      memset(inq,0,sizeof(inq));
      dist[s]=0;
      queue<int> q;
      q.push(s);
      inq[s]=1;
      MM(prev,-1);
      while(!q.empty())
      {
          int u=q.front();
          q.pop();inq[u]=0;
          for(int j=0;j<G[u].size();j++)
            {
                edge &e=G[u][j];
                if(e.cap>0&&dist[e.to]>dist[u]+e.cost)
                   {
                       dist[e.to]=dist[u]+e.cost;
                       prev[e.to]=u;
                       prel[e.to]=j;
                       if(!inq[e.to])
                       {
                           q.push(e.to);
                           inq[e.to]=1;
                       }
                   }
            }
       }
       for(int i=t;i>s;)
       {
           int f=prev[i];
           if(f==-1) return -1;
           int j=prel[i];
           G[f][j].cap-=1;
           G[i][G[f][j].rev].cap+=1;
           ans+=G[f][j].cost;
           i=prev[i];
       }
       f-=1;
    }
    return ans;
}

void build()
{
    for(int i=0;i<=cnth+cntm+1;i++) G[i].clear();
    for(int i=1;i<=cntm;i++)
          add_edge(0,i,1,0);
    for(int i=1;i<=cnth;i++)
          add_edge(cntm+i,cntm+cnth+1,1,0);
    for(int i=1;i<=cntm;i++)
          for(int j=1;j<=cnth;j++)
        {
          int dis=abs(house[j].x-men[i].x)+abs(house[j].y-men[i].y);
          add_edge(i,j+cntm,1,dis);
        }
}

char s[105][105];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m)&&(n||m))
    {
        cnth=cntm=0;
        for(int i=1;i<=n;i++)
           {
               scanf("%s",s[i]);
               for(int j=0;j<m;j++)
                   if(s[i][j]==‘H‘)
                      house[++cnth]=(Point){i,j+1};
                   else if(s[i][j]==‘m‘)
                      men[++cntm]=(Point){i,j+1};
           }
        build();
        printf("%d\n",mincost(0,cnth+cntm+1,cnth));
    }
    return 0;
}

  分析:建图有一点点技术含量,人放左边,门放右边,加一个源点与汇点,然后跑一跑大小为人数(门数)的最小费用流就好,

时间: 2024-11-17 07:51:32

POJ 2195 一人一房 最小费用流 建图 水题的相关文章

POJ 2195 Going Home【最小费用流 二分图最优匹配】

题目大意:一个n*m的地图,上面有一些人man(m)和数量相等的house(H) 图上的距离为曼哈顿距离 问所有人住进一所房子(当然一个人住一间咯)距离之和最短是多少? 思路:一个人一间房,明显是二分图的模型,边权为人和房子的曼哈顿距离,然后算一下最小距离即可 懒得学KM了 最小费用流的经典建图 #include #include #include #include #include #define maxn 40000 #define inf 0x3f3f3f3f using namespac

POJ 2312Battle City(BFS-priority_queue 或者是建图spfa)

1 /* 2 bfs搜索!要注意的是点与点的权值是不一样的哦! 3 空地到空地的步数是1, 空地到墙的步数是2(轰一炮+移过去) 4 所以用到优先队列进行对当前节点步数的更新! 5 */ 6 #include<iostream> 7 #include<queue> 8 #include<cstring> 9 #include<algorithm> 10 #include<cstdio> 11 using namespace std; 12 13

POJ 3281 Dining(最大流建图 &amp;&amp; ISAP &amp;&amp; 拆点)

题目链接:http://poj.org/problem?id=3281 努力练建图ing!!! 题意:有 N 头牛,有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料. 第2行-第N+1行.是牛i 喜欢A种食物,B种饮料,及食物种类列表和饮料种类列表. 问最多能使几头牛同时享用到自己喜欢的食物和饮料.->最大流. 本题难点是建图: 思路:一般都是左边一个集合表示源点与供应相连,右边一个集合表示需求与汇点相连. 但是本题,牛作为需求仍然是一个群体,但是供

POJ 1269 Intersecting Lines(线段相交,水题)

Intersecting Lines 大意:给你两条直线的坐标,判断两条直线是否共线.平行.相交,若相交,求出交点. 思路:线段相交判断.求交点的水题,没什么好说的. struct Point{ double x, y; } ; struct Line{ Point a, b; } A, B; double xmult(Point p1, Point p2, Point p) { return (p1.x-p.x)*(p2.y-p.y)-(p1.y-p.y)*(p2.x-p.x); } bool

POJ - 3006 - Dirichlet&#39;s Theorem on Arithmetic Progressions = 水题

http://poj.org/problem?id=3006 给一个等差数列,求其中的第n个质数,答案保证不超过1e6.n还特别小?!!! 埃筛之后暴力. #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set> #include<stack

POJ 2226 最小点覆盖(经典建图)

Muddy Fields Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8881   Accepted: 3300 Description Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <= 50). While good for the grass, t

POJ 3026:Borg Maze(BFS建图+prim+MST)

Borg Maze Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8250   Accepted: 2762 Description The Borg is an immensely powerful race of enhanced humanoids from the delta quadrant of the galaxy. The Borg collective is the term used to descr

POJ 1161 Walls(Floyd , 建图)

题意: 给定n个城市, 然后城市之间会有长城相连, 长城之间会围成M个区域, 有L个vip(每个vip会处于一个城市里)要找一个区域聚会, 问一共最少跨越多少个长城. 分析: 其实这题难就难在建图, 因为图中的点不再是城市, 而是城市之间长城围成的区域, 只要把区域提取出来, 这题就是简单的Floyd了. 我们可以把每个区域的边先记录下来, 然后有共边的就是相邻的区域, vip所在的城市都是vip的出发区域,枚举聚会区域,然后都可能的vip区域都求一次取最少值再求和即可. #include<io

POJ 2342 &amp;&amp;HDU 1520 Anniversary party 树形DP 水题

一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点)都不能被邀请 2.每一个员工都有一个兴奋值,在满足1的条件下,要使得邀请来的员工的兴奋值最高 输出最高的兴奋值. 简单的树形DP dp[i][1]:表示以i为根的子树,邀请节点i的最大兴奋值 dp[i][0]:表示以i为根的子树,不邀请节点i的最大兴奋值 先根据入度找出整棵树的根节点, 然后一次DF