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\n", min_cost_flow(s, t));
    }
    return 0;
}

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

时间: 2024-10-15 23:52:21

POJ-2195 Going Home(最小费用最大流模板)的相关文章

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

题目链接:http://poj.org/problem?id=2195 题意:n*m的矩阵,地图上有若干个人(m)和房子(H),且人与房子的数量一致.man每移动一格费用为1,一个房子只能住一个人.现在要求所有的人出发,都入住房子,求最少话费. 思路:建立一个超级源点和汇点,源点与人相连费用为0,容量为1,人与房子相连,费用为人与房子的距离,容量为1,房子与汇点相连,费用为0,容量为1 #include <iostream> #include <cstdlib> #include

POJ 2195 地图的最小费用最大流

思路:这题刚开始看就知道是最小费用最大流了,因为求出最优嘛,而且要m,H要一一对应,所以不是二分图匹配就是最小费用最大流. 不过,刚开始还在想每个m与H之间的最小花费如何求,难道要用dfs搜索吗?这样想之后看了下题目给的时间是1000ms,然后就把dfs搜索m与H之间的最短距离排除了.然后想了想,其实尼玛太简单了,因为题目说了只能垂直与竖直的走,所以最短距离不就是两个横坐标相减与两个纵坐标相减之和嘛! 然后每对m与H之间都连边,流量为1(因为每对匹配不能重复),费用为它们之间的距离即花费:然后建

POJ 2195 - Going Home - [最小费用最大流][MCMF模板]

题目链接:http://poj.org/problem?id=2195 Time Limit: 1000MS Memory Limit: 65536K 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

POJ 2195 Going Home 最小费用最大流 尼玛,心累

D - Going Home Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2195 Appoint description: Description On a grid map there are n little men and n houses. In each unit time, every little man can mo

POJ 2516 Minimum Cost(最小费用最大流,坑题)

题目链接:http://poj.org/problem?id=2516 题意:有N个店,M个供货商,K种商品.已知供货商的仓库里每种商品的数量以及每种商品运送到每个店的费用,每个店铺对各种商品的需求数量,求最少话费. Input  第一行:N,M,K. 然后1 - N行,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件. 然后 N+1 - M行  ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件. 然后是K个矩阵  ,每个N行M列,第ji个矩阵的第i行第j

poj 2135 Farm Tour (最小费用最大流模板)

网络流的费用: 在实际应用中,与网络流有关的问题,不仅涉及流量,而且还有费用的因素.网络的每一条边(v,w)除了给定容量cap(v,w)外,还定义了一个单位流量费用cost(v,w) 最小费用最大流问题 给定网络G,要求G的一个最大用流flow,使流的总费用最小. 求解MCMF问题的算法: 最小费用最大流最常用和基本的算法我们可以称它为最小费用路算法,其思想与求最大流的增广路算法类似,不断在残流网络中寻找从源s到汇t的最小费用路,即残流网络中从s到t的以费用为权的最短路,然后沿最小费用路增流,直

POJ2135Farm Tour(最小费用最大流模板)

题目链接:http://poj.org/problem?id=2135 题意:农场主想从1到n,然后从n到1,每条边最多走一次,不能走重复的路,问最短距离是多少. 建图:取超级源点s,并与房子连一条边,容量为2,费用为0:取barn与超级汇点 t 的边的容量为2,费用为0 房子与barn的费用为距离,容量为1 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring>

POJ2135 最小费用最大流模板题

练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include <cstring> #define MAXN 1005 #define MAXM 10005 #define INF 0x3f3f3f3f struct Edge { int y,c,w,ne;//c容量 w费用 }e[MAXM*4]; int n,m,x,y,w; int s,t,Maxflow

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

POJ 2516 Minimum Cost (最小费用最大流)

Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K       Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy