zoj 3362 Beer Problem 【最大费用最大流 需要判断最长路值是否为负】

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.


Author:  Andrew Stankevich

Source: Andrew Stankevich's Contest #11



题意:有N个城市以及连接这些城市的M条无向边,其中城市1是啤酒产地。给出N-1个数字,分别表示每个城市里啤酒每桶的价格(城市1不算),我们可以认为这N-1个城市对啤酒的需求是没有限制的即 无限大。

已知每条无向边最多可以运送啤酒的桶数 和运送每桶的花销,问你从城市1出发卖啤酒可以得到的最大收益。



思路:最大费用流。每次SPFA找最长路,找到后寻找最小可行流,然后增广路径。直到不存在源点到汇点的最长路或者最长路为负时停止。


建图:设置一个超级源点source和超级汇点sink。

1,source到城市1建边,容量为无穷,费用为0;

2,所有城市向超级汇点sink建边,容量为无穷,费用为该城市每桶啤酒的价格。只要我们愿意,可以选择任意桶数的啤酒在这个城市卖出;

3,M条无向边<u, v>,建双向边,容量为最多运送啤酒的桶数,费用为运送每桶花销的相反数。


再次提醒下:最长路为负值时说明该路径上的所有边权之和为负值,更直白的说亏本了!这时就要停止增广。




AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define MAXN 210
#define MAXM 10000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int pre[MAXN], dist[MAXN];
bool vis[MAXN];
int source, sink;//超级源点 超级汇点
int N, M;//城市数 边数
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w, int c)
{
    Edge E1 = {u, v, w, 0, c, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
    Edge E2 = {v, u, 0, 0, -c, head[v]};
    edge[edgenum] = E2;
    head[v] = edgenum++;
}
void getMap()
{
    source = 0, sink = N+1;
    int a, b, c, d;
    addEdge(source, 1, INF, 0);
    for(int i = 2; i <= N; i++)
    {
        scanf("%d", &a);
        addEdge(i, sink, INF, a);//容量无穷大 因为每个城市的需求是没有限制的
    }
    while(M--)
    {
        scanf("%d%d%d%d", &a, &b, &c, &d);
        addEdge(a, b, c, -d);//建双向边
        addEdge(b ,a, c, -d);
    }
}
bool SPFA(int s, int t)
{
    queue<int> Q;
    memset(dist, -INF, sizeof(dist));
    memset(vis, false, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    dist[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            if(dist[E.to] < dist[u] + E.cost && E.cap > E.flow)//寻找最长路 且 路径上不能有满流的边
            {
                dist[E.to] = dist[u] + E.cost;
                pre[E.to] = i;
                if(!vis[E.to])
                {
                    vis[E.to] = true;
                    Q.push(E.to);
                }
            }
        }
    }
    return pre[t] != -1 && dist[t] >= 0;//最长路不能是负的 要不会赔钱
}
void MCMF(int s, int t, int &cost)
{
    cost = 0;
    while(SPFA(s, t))
    {
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            Edge E = edge[i];
            Min = min(Min, E.cap-E.flow);
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i].cost * Min;
        }
    }
}
int main()
{
    while(scanf("%d%d", &N, &M) != EOF)
    {
        init();
        getMap();
        int cost;
        MCMF(source, sink, cost);
        printf("%d\n", cost);
    }
    return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值