zoukankan      html  css  js  c++  java
  • POJ-2195 Going Home(最小费用最大流模板)

    题目链接:POJ-2195 Going Home

    题意

    给出$N$行$M$列的网格,'m'表示人,'H'表示房子,且'm'和'H'的数量相同,一个人只能进一间房子,一间房子也只能给一个人进去,人可走上下左右四个方向,现在要让所有人进入房子,求最短路径和。


    思路

    这是一个二分图带权最小匹配问题,可直接用最小费用最大流求解。

    源点向人各连一条容量为1,费用为0的边,每个人向每间房子连容量为1,费用为距离的边,每间房子向汇点连容量为1,费用为0的边,然后跑最小费用最大流即可。


    代码实现

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cstdlib>
    #include <cstring>
    #define N 5000
    using namespace std;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int to, cap, cost, rev;
        Edge(int t, int c, int cc, int r) :to(t), cap(c), cost(cc), rev(r){}
    };
    int V;
    vector<Edge> G[N];
    int h[N];
    int dist[N];
    int prevv[N];
    int preve[N];
    
    void addedge(int from, int to, int cap, int cost)
    {
        G[from].push_back(Edge(to, cap, cost, G[to].size()));
        G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1 ));
    }
    int min_cost_flow(int s, int t)
    {
        int res = 0;
        fill(h, h + V, 0);
        while (true)
        {
            priority_queue<P, vector<P>, greater<P> >q;
            fill(dist, dist + V, INF);
            dist[s] = 0;
            q.push(P(0, s));
            while (!q.empty())
            {
                P p = q.top(); q.pop();
                int v = p.second;
                if (dist[v] < p.first)continue;
                for (int i = 0; i < G[v].size(); i++)
                {
                    Edge &e = G[v][i];
                    if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to])
                    {
                        dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        q.push(P(dist[e.to], e.to));
                    }
                }
            }
            if (dist[t] == INF) break;
            for (int j = 0; j < V; j++)
                h[j] += dist[j];
            int d = INF;
            for (int x = t; x != s; x = prevv[x])
                d = min(d, G[prevv[x]][preve[x]].cap);
            if (d == 0) break;
            res += d * h[t];
            for (int x = t; x != s; x = prevv[x])
            {
                Edge &e = G[prevv[x]][preve[x]];
                e.cap -= d;
                G[x][e.rev].cap += d;
            }
        }
        return res;
    }
    
    int main()
    {
        int n, m;
        while (~scanf("%d %d", &n, &m) && n && m) {
            vector<P> hou, man;
            char ch;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    scanf(" %c", &ch);
                    if (ch == 'H') hou.push_back(make_pair(i, j));
                    else if (ch == 'm') man.push_back(make_pair(i, j));
                }
            }
            int cnt = hou.size();
            V = 2 * cnt + 2;
            int s = 2 * cnt, t = 2 * cnt + 1;
            for (int i = 0; i < V + 10; i++) G[i].clear();
            for (int i = 0; i < cnt; i++) {
                for (int j = 0; j < cnt; j++) {
                    addedge(i, cnt + j, 1, abs(man[i].first - hou[j].first) + abs(man[i].second - hou[j].second));
                }
            }
            for (int i = 0; i < cnt; i++) {
                addedge(s, i, 1, 0);
                addedge(cnt + i, t, 1, 0);
            }
            printf("%d
    ", min_cost_flow(s, t));
        }
        return 0;
    }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    WHERE col1=val1 AND col2=val2;index exists on col1 and col2, the appropriate rows can be fetched directly
    MySQL 交集 实现方法
    MBProgressHUD的使用
    Xcode4 使用 Organizer 分析 Crash logs(转)
    SimpleXML 使用详细例子
    PHP的XML Parser(转)
    iPhone,iPhone4,iPad程序启动画面的总结 (转)
    Pop3得到的Email 信件格式介绍
    yii总结
    隐藏Tabbar的一些方法
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11324602.html
Copyright © 2011-2022 走看看