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 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

题意:给一个地图,标了人m和房H的位置,人数和房子数量相等,现在所有人要回各自的家,一个房只能容一个人。问所有人走的步数总和最少是多少?每一步只能走相邻的格子。

解题:最小费用流。

分3类点:1:源点S,汇点T。 2:人M。3:房H。

建图:(u , v  , cap, cost):u-->v边容为cap,花费为cost

1):(S , M , 1 , 0)

2):(M , H , 1 , mindis):mindis表示人到房的最短距离

3:(H , T , 1 , 0)

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN = 10010;
const int MAXM = 100100;
const int INF = 1<<30;
struct EDG{
    int to,next,cap,flow;
    int cost;  //单价
}edg[MAXM];
int head[MAXN],eid;
int pre[MAXN], cost[MAXN]  ; //点0~(n-1)

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
void addEdg(int u,int v,int cap,int cst){
    edg[eid].to=v; edg[eid].next=head[u]; edg[eid].cost = cst;
    edg[eid].cap=cap; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v]; edg[eid].cost = -cst;
    edg[eid].cap=0; edg[eid].flow=0; head[v]=eid++;
}

bool inq[MAXN];
bool spfa(int sNode,int eNode,int n){
    queue<int>q;
    for(int i=0; i<n; i++){
        inq[i]=false; cost[i]= INF;
    }
    cost[sNode]=0; inq[sNode]=1; pre[sNode]=-1;
    q.push(sNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        inq[u]=0;
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && cost[v]>cost[u]+edg[i].cost){ //在满足可增流的情况下,最小花费
                cost[v] = cost[u]+edg[i].cost;
                pre[v]=i;   //记录路径上的边
                if(!inq[v])
                    q.push(v),inq[v]=1;
            }
        }
    }
    return cost[eNode]!=INF;    //判断有没有增广路
}
//反回的是最大流,最小花费为minCost
int minCost_maxFlow(int sNode,int eNode ,int& minCost,int n){
    int ans=0;
    while(spfa(sNode,eNode,n)){
        int mint=INF;
        for(int i=pre[eNode]; i!=-1; i=pre[edg[i^1].to]){
            if(mint>edg[i].cap-edg[i].flow)
                mint=edg[i].cap-edg[i].flow;
        }
        ans+=mint;
        for(int i=pre[eNode]; i!=-1; i=pre[edg[i^1].to]){
            edg[i].flow+=mint; edg[i^1].flow-=mint;
            minCost+=mint*edg[i].cost;
        }
    }
    return ans;
}

int abs(int a){ return a>0?a:-a; }
int buildGraph(char mapt[105][105],int n,int m){

    int id[105][105] , k=1 ;

    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        if(mapt[i][j]=='H'||mapt[i][j]=='m')
         id[i][j]=k++;
    int s=0 , t = k;
    for(int i=0; i<n; i++)
    for(int j=0; j<m; j++)
    if(mapt[i][j]=='m'){

        int u,v;
        u=id[i][j];
        addEdg(s,u,1,0);

        for(int ti=0; ti<n; ti++)
            for(int tj=0; tj<m; tj++)
            if(mapt[ti][tj]=='H'){
                v=id[ti][tj];
                addEdg(u,v,1,abs(ti-i)+abs(tj-j));
            }
    }
    else if(mapt[i][j]=='H')
        addEdg(id[i][j],t,1,0);
    return k;
}
int main(){
      int n,m;
      char mapt[105][105];

      while(scanf("%d%d",&n,&m)>0&&(n||m)){
            for(int i=0; i<n; i++)
                scanf("%s",mapt[i]);
            init();
            int s=0,t=buildGraph(mapt,n,m) , minCost=0;

            minCost_maxFlow(s,t,minCost,t+1);

            printf("%d\n",minCost);
      }
}
时间: 2024-11-03 05:33:37

HDU 1533 Going Home(最小费用流)的相关文章

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 horizon

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

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

HDU 1533 Going Home(KM完美匹配)

HDU 1533 Going Home 题目链接 题意:就是一个H要对应一个m,使得总曼哈顿距离最小 思路:KM完美匹配,由于是要最小,所以边权建负数来处理即可 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXNODE = 105; typedef int Type; const T

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

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

hdu 1533 Going Home (KM算法)

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

【HDU 1533】 Going Home (KM)

Going Home 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 f

Going Home HDU - 1533 (费用流)

Going Home HDU - 1533 1 //费用流初探 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #include <cstdio> 6 #include <algorithm> 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 110; 10 char gra

Going Home (hdu 1533 最小费用流)

集训的图论都快结束了,我才看懂了最小费用流,惭愧啊. = = 但是今天机械键盘到了,有弄好了自行车,好高兴\(^o^)/~ 其实也不是看懂,就会套个模板而已.... 这题最重要的就是一个: 多组输入一定要写个init()函数清空,并且输入的时候每次都要调用init() #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include &

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,