poj - 2195 - Going Home

题意:有n个人,n个房子,一个人每走一步(可上、下、左、右取一个方向)花费1美元,问让这n个人走到n个房子里最少需要多少美元(n <= 100)。

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

——>>在学最小费用最大流,找模版题找到了这道。

建图:1到n为人的编号,n+1到2*n为房子的编号,另加上源点0和汇点2*n+1;

源点到每个人各建立一条容量为1的流,费用为0;

每个人到每个房子各建立一条容量为1的流,费用按题意计算;(注意:反向费用!!!)

每个房子到汇点建立一条容量为1的流,费用为0。

当满足最大流时,一定是源点发出n,每个人接收1并发出1到一个房子,n个房子各发出1汇成n到汇点,所以,真是最小费用最大流的模版题。

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int maxn = 2 * (100 + 10);
const int INF = 0x3f3f3f3f;

struct node{        //结点类型
    int x;
    int y;
}m[maxn], h[maxn];

int N, M, n, t, mid, hid, cost[maxn][maxn], cap[maxn][maxn], flow[maxn][maxn], p[maxn];
vector<node> man, house;

void init(){        //初始化
    mid = 0;
    hid = 0;
    memset(cost, 0, sizeof(cost));
    memset(cap, 0, sizeof(cap));
}

void build(){       //建图
    n = mid;
    t = mid + hid + 1;
    int i, j;
    for(i = 1; i <= n; i++){
        for(j = 1; j <= n; j++){
            cap[i][j+n] = 1;
            cost[i][j+n] = abs(m[i].x - h[j].x) + abs(m[i].y - h[j].y);
            cost[j+n][i] = -cost[i][j+n];       //注意这里加上回流!!!
        }
    }
    for(i = 1; i <= n; i++) cap[0][i] = 1;
    for(i = n+1; i < t; i++) cap[i][t] = 1;
}

int solve(int s){
    queue<int> qu;
    int d[maxn];
    memset(flow, 0, sizeof(flow));
    int c = 0;
    for(;;){
        bool inq[maxn];
        memset(d, 0x3f, sizeof(d));
        d[0] = 0;
        memset(inq, 0, sizeof(inq));
        qu.push(s);
        while(!qu.empty()){
            int u = qu.front(); qu.pop();
            inq[u] = 0;
            for(int v = 0; v <= t; v++) if(cap[u][v] > flow[u][v] && d[u] + cost[u][v] < d[v]){
                d[v] = d[u] + cost[u][v];
                p[v] = u;
                if(!inq[v]){
                    qu.push(v);
                    inq[v] = 1;
                }
            }
        }
        if(d[t] == INF) break;
        int a = INF;
        for(int u = t; u != s; u = p[u]) a = min(a, cap[p[u]][u] - flow[p[u]][u]);
        for(int u = t; u != s; u = p[u]){
            flow[p[u]][u] += a;
            flow[u][p[u]] -= a;
        }
        c += d[t] * a;
    }
    return c;
}

int main()
{
    int i, j;
    char c;
    while(scanf("%d%d", &N, &M) == 2){
        if(!N && !M) return 0;
        init();
        for(i = 0; i < N; i++){
            getchar();
            for(j = 0; j < M; j++){
                c = getchar();
                if(c == 'H') h[++hid] = (node){i, j};
                if(c == 'm') m[++mid] = (node){i, j};
            }
        }
        build();
        printf("%d\n", solve(0));
    }
    return 0;
}


 

 

posted @ 2013-08-03 22:33  坚固66  阅读(168)  评论(0编辑  收藏  举报