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;

}


 

 

你可能感兴趣的:(home)