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
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    hiho 103 平衡树·Treap
    HDU 5738 Eureka
    codeforces 682D Alyona and Strings
    Photoshop cs5 永久序列号
    httpd.exe你的电脑中缺失msvcr110.dll怎么办
    Gzip压缩启用图文方法详细说明
    帝国CMS开启全站搜索功能
    怎么给电脑统一设置查看文件为列表形式?
    帝国CMS网站地图sitemap的制作教程,分享2种帝国cms网站地图模板
    lol安装包打开没反应
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11324602.html
Copyright © 2011-2022 走看看