码迷,mamicode.com
首页 > 其他好文 > 详细

POJ-2195 Going Home(最小费用最大流模板)

时间:2019-08-09 01:43:08      阅读:98      评论:0      收藏:0      [点我收藏+]

标签:div   view   mes   char   cos   scan   直接   onclick   问题   

题目链接: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\n", min_cost_flow(s, t));
    }
    return 0;
}
View Code

 

POJ-2195 Going Home(最小费用最大流模板)

标签:div   view   mes   char   cos   scan   直接   onclick   问题   

原文地址:https://www.cnblogs.com/kangkang-/p/11324602.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!