poj 2195//hdu 1533 Going Home 最小费用流(spfa)


Language:
Default

Going Home

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 18601   Accepted: 9500

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的图上有若干个人‘m’和房屋‘H’,人每走一步消耗一块钱,现在要让所有的人都进到房子去,一人一间房,问最小的费用是多少。

思路:最小费用流,添加超级源点和超级汇点建图,我用的spfa版费用流算法。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
using namespace std;
/*最小费用最大流,求最大费用只需要取相反数,结果取相反数即可。
点的总数为N,点的编号0~N-1*/
const int MAXN = 300;
const int MAXM = 100000;

struct Node
{
    int x,y;
}H[MAXN],M[MAXN];

struct Edge
{
    int to,next,cap,flow,cost;
}edge[MAXM];

int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N,n,m;

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 main()
{
    char ch;
    while (scanf("%d%d",&n,&m)&&(m||n))
    {
        int hh=1,mm=1;
        getchar();
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                scanf("%c",&ch);
                if (ch=='H')
                {
                    H[hh].x=i;
                    H[hh++].y=j;
                }
                else if (ch=='m')
                {
                    M[mm].x=i;
                    M[mm++].y=j;
                }
            }
            getchar();
        }
        N=hh+mm+2;
        init(N);
        mm--,hh--;
        for (int i=1;i<=mm;i++)
            addedge(0,i,1,0);
        for (int i=1;i<=hh;i++)
            addedge(i+mm,N-1,1,0);
        for (int i=1;i<=mm;i++)
        {
            for (int j=1;j<=hh;j++)
            {
                int x=abs(M[i].x-H[j].x)+abs(M[i].y-H[j].y);
                addedge(i,j+mm,1,x);
            }
        }
        int ans;
        int y=minCostMaxflow(0,N-1,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-10-19 19:46:26

poj 2195//hdu 1533 Going Home 最小费用流(spfa)的相关文章

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,

HDU 1533 Going Home(最小费用流)

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

POJ 2195 Going Home / HDU 1533(最小费用最大流模板)

题目大意: 有一个最大是100 * 100 的网格图,上面有 s 个 房子和人,人每移动一个格子花费1的代价,求最小代价让所有的人都进入一个房子.每个房子只能进入一个人. 算法讨论: 注意是KM 和 MCMF算法,我写的是MCMF算法,一开始想的是连10000个点,但是不会连那些大众点之间的边,只会连超级点和普通点之间的边.后来觉得只要连房子点和 人点就可以了.连从人到房子的边,容量是1,花费是他们之间的曼哈顿距离,然后超级源点和超级汇点像上面那样连接,注意连点的时候把他们每个点都具体化一下,就

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

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

HDU 3488Tour(网络流之最小费用流)

题目地址:hdu3488 这题跟上题基本差不多啊....详情请戳这里. 另外我觉得有要改变下代码风格了..终于知道了为什么大牛们的代码的变量名都命名的那么长..我决定还是把源点与汇点改成source和sink吧..用s和t太容易冲突了...于是如此简单的一道题调试到了现在..sad... 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #

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 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 1201 &amp;&amp; HDU 1384 Intervals(差分约束系统)

题目地址:POJ 1201   HDU 1384 根据题目意思,可以列出不等式如下: Sj-Si>=c; Si-S(i-1)>=0; S(i-1)-Si>=-1; 然后用最短路spfa来解决这个不等式.用max来当源点,0为终点.最终的-d[0]就是答案. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,