• ZOJ 3362 Beer Problem(SPFA费用流应用)


    Beer Problem

    Time Limit: 2 Seconds      Memory Limit: 32768 KB

    Everyone knows that World Finals of ACM ICPC 2004 were held in Prague. Besides its greatest architecture and culture, Prague is world famous for its beer. Though drinking too much is probably not good for contestants, many teams took advantage of tasting greatest beer for really low prices.

    A new beer producing company Drink Anywhere is planning to distribute its product in several of the n European cities. The brewery is located near Prague, that we would certainly call city number 1. For delivering beer to other cities, the company is planning to use logistics company Drive Anywhere that provides m routes for carrying goods. Each route is described by the cities it connects (products can be transported in either direction), its capacity --- the number of barrels of beer that can be transported along this route each day, and the cost of transporting one barrel of beer along it. To deliver beer to some city it may be necessary (or advantageous) to use several routes consequently, and maybe even deliver beer using several different paths.

    Each city is in turn characterized by the price that local pubs and restaurants are ready to pay for one barrel of beer. You may assume that demand for beer is essentially unlimited in each city, since this is the product that will always find its consumer.

    Drink Anywhere is not planning to distribute its beer in Prague for a while, because of the high competition there, so it is just planning to provide beer to other cities for now. Help it to find out, what is the maximal income per day it can get.

    Input

    The first line of the input file contains n and m --- the number of cities in Europe we consider and the number of delivery routes respectively (2 ≤ n ≤ 100), 1 ≤ m ≤ 2000). The next line contains n - 1 integer numbers --- prices of a barrel of beer in European cities 2, 3 ..., n respectively (prices are positive integers and do not exceded 1000).

    The following m lines contain four integer numbers each and describe delivery routes. Each route is specified by the numbers of cities it connects, its capacity, and the price of transporting one barrel of beer along it (the capacity and the price are positive integers, they do not exceed 1000).

    There are multiple cases. Process to the end of file.

    Output

    Output the maximal income the company can get each day.

    Sample Input

    4 4
    80 50 130
    1 2 80 50
    2 4 40 90
    3 1 40 60
    3 4 30 50
    

    Sample Output

    3000
    

    Hint

    The company should deliver 80 barrels of beer to the second city (using the first route it costs 50 per barrel to deliver beer, income is 30 per barrel, 2400 total), and 30 barrels to the fourth city (the best path uses routes 3 and 4, it costs 110 to deliver a barrel, income is 20 per barrel, 600 total). It is not profitable to deliver beer to the third city, so the company should not do it.

    题目链接:ZOJ 3362

    建图:构建源点S为0和汇点T为n+1,从S到1连一条流量为INF费用为0的边,然后由于可以卖无限多的酒给每一个城市,因此城市到汇点连一条流量为INF费用为正的该城市的售价的边,然后对于M条边添加双向边,流量均为所给的cap,费用均为负的单位运输费用。正负怎么看呢?由于我们求的是最大费用,但算法求的是最小费用流,因此把原来的边上的正的费用要取负值,但是售价又和运输费用相反,负负得正为正值。

    然后这题一开始以为求的是最大费用最大流,但是当达到最大流的时候赚的钱却只有2900,且问题就出在多出来的10流量上,调试后发现当处理这10个流量的时候费用已经是负的了,因此当费用为负的时候就不要再进行增广即可。为什么一旦为负就可以不用再进行增广了呢?可以这样想,第一次增广的时候找到了可行流,然后从图中减掉了它,开始第二次增广,这时S到T的最短路肯定会由于残余流量的影响,至少这个最短距离是不会变短的,因此每一次增广费用距离总是不减的,当求最大费用的时候,显然就是不增的了,即保证了d[t]一旦为负后面均为负数且不会增大。

    代码:

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LC(x) (x<<1)
    #define RC(x) ((x<<1)+1)
    #define MID(x,y) ((x+y)>>1)
    #define CLR(arr,val) memset(arr,val,sizeof(arr))
    #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
    typedef pair<int, int> pii;
    typedef long long LL;
    const double PI = acos(-1.0);
    const int N = 110;
    const int M = 2010;
    struct edge
    {
        int to, nxt, cap, cost;
        edge() {}
        edge(int _to, int _nxt, int _cap, int _cost): to(_to), nxt(_nxt), cap(_cap), cost(_cost) {}
    };
    edge E[(N + 2 * M) << 1];
    int head[N], tot;
    int d[N], pre[N], path[N];
    bitset<N>vis;
    int mc, mf;
    
    void init()
    {
        CLR(head, -1);
        tot = 0;
        mc = mf = 0;
    }
    inline void add(int s, int t, int cap, int cost)
    {
        E[tot] = edge(t, head[s], cap, cost);
        head[s] = tot++;
        E[tot] = edge(s, head[t], 0, -cost);
        head[t] = tot++;
    }
    int spfa(int s, int t)
    {
        CLR(d, -INF);
        int inf = d[0];
        vis.reset();
        CLR(pre, -1);
        CLR(path, -1);
        d[s] = 0;
        vis[s] = 1;
        queue<int>q;
        q.push(s);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for (int i = head[u]; ~i; i = E[i].nxt)
            {
                int v = E[i].to;
                if (d[v] < d[u] + E[i].cost && E[i].cap > 0)
                {
                    d[v] = d[u] + E[i].cost;
                    pre[v] = u;
                    path[v] = i;
                    if (!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
        return d[t] != inf;
    }
    void MCMF(int s, int t)
    {
        int i;
        while (spfa(s, t))
        {
            int Min = INF;
            for (i = t; i != s && ~i; i = pre[i])
                Min = min(Min, E[path[i]].cap);
            for (i = t; i != s && ~i; i = pre[i])
            {
                E[path[i]].cap -= Min;
                E[path[i] ^ 1].cap += Min;
            }
            if (d[t] < 0)
                return ;
            mf += Min;
            mc += Min * d[t];
        }
    }
    int main(void)
    {
        int n, m, a, b, c, d, i;
        while (~scanf("%d%d", &n, &m))
        {
            init();
            int S = 0, T = n + 1;
            add(S, 1, INF, 0); //1
            for (i = 2; i <= n; ++i)
            {
                scanf("%d", &d);
                add(i, T, INF, d); //n
            }
            for (i = 0; i < m; ++i)
            {
                scanf("%d%d%d%d", &a, &b, &c, &d);
                add(a, b, c, -d); //m
                add(b, a, c, -d); //m
            }
            MCMF(S, T);
            printf("%d
    ", mc);
        }
        return 0;
    }
  • 相关阅读:
    一对一关联
    一对多关联
    软删除
    分层控制器
    系统的助手函数
    tp5命令行基础介绍
    PHP 开启跨域
    生成数据库模型文件
    REST API 安全设计指南
    jquery-Ajax请求用例码
  • 原文地址:https://www.cnblogs.com/Blackops/p/6358113.html
Copyright © 2020-2023  润新知