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


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

  • 相关阅读:
    Vue cli 安装慢的原因和解决记录
    spring-boot
    illustrator 2018 cc
    illustrator 2018 cc
    illustrator 2018 cc
    illustrator 2018 cc- 画板技巧
    Tomcat 用户密码配置
    CentOS7上解决tomcat不能被外部浏览访问
    Ubuntu
    SPI、I2C、UART(转)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4823858.html
Copyright © 2011-2022 走看看