zoukankan      html  css  js  c++  java
  • POJ2195 Going Home 【最小费用流】+【最佳匹配图二部】

    Going Home
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 18169   Accepted: 9268

    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

    题意:给定一张N*M的图。当中‘.’为空地,小人能够走,‘m’为小人,‘H’为房子。小人能够路过。小人一次仅仅能沿着上下左右走一个格子。如今要求每一个小人都进入一个不同的房子。求小人走的步数最小数。

    题解:这题能够看成最小费用流来解,当中小人到房子的距离为费用,容量为1。设置源点到每一个小人的容量为1。费用为0,每一个房子到汇点费用为0。容量为1,剩下的就是求最小费用流了。

    版本号一:最小费用流:125ms

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <queue>
    
    const int maxn = 205;
    const int inf = 0x3f3f3f3f;
    char str[maxn];
    int head[maxn], n, m; // n rows, m columns
    struct Node {
        int x, y;
    } A[maxn], B[maxn];
    int id1, id2, id, source, sink;
    struct node {
        int f, c, u, v, next;
    } E[maxn * maxn];
    bool vis[maxn];
    int pre[maxn], dist[maxn];
    
    void addEdge(int u, int v, int c, int f) {
        E[id].u = u; E[id].v = v;
        E[id].c = c; E[id].f = f;
        E[id].next = head[u]; head[u] = id++;
    
        E[id].u = v; E[id].v = u;
        E[id].c = 0; E[id].f = -f;
        E[id].next = head[v]; head[v] = id++;
    }
    
    void getMap() {
        int i, j, dis; Node e; 
        id = id1 = id2 = 0;
        for(i = 0; i < n; ++i) {
            scanf("%s", str);
            for(j = 0; str[j] != ''; ++j) {
                if(str[j] == '.') continue;
                e.x = i; e.y = j;
                if(str[j] == 'm') A[id1++] = e;
                else B[id2++] = e;
            }
        }
    
        memset(head, -1, sizeof(head));
        source = id1 + id2; sink = source + 1;
        for(i = 0; i < id1; ++i) {
            for(j = 0; j < id2; ++j) {
                dis = abs(A[i].x - B[j].x) + abs(A[i].y - B[j].y);
                addEdge(i, id1 + j, 1, dis); // uvcf
            }
            addEdge(source, i, 1, 0);
        }
        for(j = 0; j < id2; ++j)
            addEdge(id1 + j, sink, 1, 0);
    }
    
    bool SPFA(int start, int end) {
        std::queue<int> Q; int i, u, v;
        memset(vis, 0, sizeof(vis));
        memset(pre, -1, sizeof(pre));
        memset(dist, 0x3f, sizeof(pre));
        Q.push(start); vis[start] = 1; dist[start] = 0;
        while(!Q.empty()) {
            u = Q.front(); Q.pop();
            vis[u] = 0;
            for(i = head[u]; i != -1; i = E[i].next) {
                v = E[i].v;
                if(E[i].c && dist[v] > dist[u] + E[i].f) {
                    dist[v] = dist[u] + E[i].f;
                    pre[v] = i;
                    if(!vis[v]) {
                        Q.push(v); vis[v] = 1;
                    }
                }
            }
        }
        return dist[end] != inf;
    }
    
    int Min_Cost_Flow(int start, int end) {
        int ans_cost = 0, u, minCut;
        while(SPFA(start, end)) {
            minCut = inf;
            for(u = pre[end]; u != -1; u = pre[E[u].u]) {
                if(minCut > E[u].c) minCut = E[u].c;
            }
            for(u = pre[end]; u != -1; u = pre[E[u].u]) {
                E[u].c -= minCut; E[u^1].c += minCut;
            }
            ans_cost += minCut * dist[end];
        }
        return ans_cost;
    }
    
    void solve() {
        printf("%d
    ", Min_Cost_Flow(source, sink));
    }
    
    int main() {
        // freopen("stdin.txt", "r", stdin);
        while(scanf("%d%d", &n, &m), n | m) {
            getMap();
            solve();
        }
        return 0;
    }

    版本号二:KM:0ms

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    const int maxn = 105;
    const int largeNum = 210;
    const int inf = 0x3f3f3f3f;
    int n, m; // n rows, m columns
    char str[maxn];
    struct Node {
        int x, y;
    } A[maxn], B[maxn];
    int id1, id2;
    int G[maxn][maxn];
    int Lx[maxn], Ly[maxn];
    int match[maxn];
    bool visx[maxn], visy[maxn];
    int slack[maxn];
    
    void getMap() {
        int i, j, dis; Node e;
        id1 = id2 = 0;
        for(i = 0; i < n; ++i) {
            scanf("%s", str);
            for(j = 0; str[j] != ''; ++j) {
                if(str[j] == '.') continue;
                e.x = i; e.y = j;
                if(str[j] == 'm') A[id1++] = e;
                else B[id2++] = e;
            }
        }
        memset(G, 0, sizeof(G));
        for(i = 0; i < id1; ++i) {
            for(j = 0; j < id2; ++j) {
                G[i][j] = largeNum - (abs(A[i].x - B[j].x) + abs(A[i].y - B[j].y));
            }
        }
    }
    
    bool DFS(int cur) {
        int t, y;
        visx[cur] = true;
        for(y = 0; y < id2; ++y) {
            if(visy[y]) continue;
            t = Lx[cur] + Ly[y] - G[cur][y];
            if(t == 0) {
                visy[y] = true;
                if(match[y] == -1 || DFS(match[y])) {
                    match[y] = cur; return true;
                }
            } else if(slack[y] > t) slack[y] = t; 
        }
        return false;
    }
    
    int KM() {
        int i, j, x, d, ret;
        memset(match, -1, sizeof(match));
        memset(Ly, 0, sizeof(Ly));
        for(i = 0; i < id1; ++i) {
            Lx[i] = -inf;
            for(j = 0; j < id2; ++j)
                if(G[i][j] > Lx[i]) Lx[i] = G[i][j];
        }
        for(x = 0; x < id1; ++x) {
            memset(slack, 0x3f, sizeof(slack));
            while(true) {
                memset(visx, 0, sizeof(visx));
                memset(visy, 0, sizeof(visy));
                if(DFS(x)) break;
                d = inf;
                for(i = 0; i < id2; ++i)
                    if(!visy[i] && d > slack[i]) 
                        d = slack[i];
                for(i = 0; i < id1; ++i)
                    if(visx[i]) Lx[i] -= d;
                for(i = 0; i < id2; ++i)
                    if(visy[i]) Ly[i] += d;
                    else slack[i] -= d;
            }
        }
        ret = 0;
        for(i = 0; i < id1; ++i)
            if(match[i] > -1) ret += G[match[i]][i];
        return ret;
    }
    
    void solve() {
        printf("%d
    ", largeNum * id1 - KM());
    }
    
    int main() {
        // freopen("stdin.txt", "r", stdin);
        while(scanf("%d%d", &n, &m), n | m) {
            getMap();
            solve();
        }
        return 0;
    }


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    EF6 Code First 模式更新数据库架构
    bootstrap-datepicker 插件修改为默认中文
    常用网络资源下载
    jQuery框架学习第十一天:实战jQuery表单验证及jQuery自动完成提示插件
    AngularJS实现原理
    [个人翻译]GitHub指导文件(GitHub Guides[Hello World])
    年后跳槽如何准备?
    前端学数据库之子查询
    Ionic实战 自动升级APP(Android版)
    读书笔记:《HTML5开发手册》Web表单
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4823858.html
Copyright © 2011-2022 走看看