ZOJ 3362--Beer Problem【最大费用最大流 && 有值得注意的地方】

来源:互联网 发布:中华网络一条龙官方 编辑:程序博客网 时间:2024/05/20 16:35

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 then 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 companyDrive 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 480 50 1301 2 80 502 4 40 903 1 40 603 4 30 50

Sample Output

3000

题意:

有N个城市以及连接这些城市的M条无向边,其中城市1是啤酒产地。给出N-1个数字,分别表示每个城市里啤酒每桶的价格(城市1不算),我们可以认为这N-1个城市对啤酒的需求是没有限制的即 无限大。
已知每条无向边最多可以运送啤酒的桶数 和运送每桶的花销,问你从城市1出发卖啤酒可以得到的最大收益。

解析:

算是比较好像的费用流了,但要注意。每次SPFA找到可以从源点到汇点的最长路后,我们还有确保到达汇点的最长路的值为正(负值相当于亏本了)时,才进行增广。

见图思路:

(1)每个城市(除城市1外,城市1最为源点处理)向汇点建边,费用为每桶啤酒的价格,容量为INF,因为是要我们想,可以这个城市卖任意多的啤酒。

(2)相互可达的两个城市建边,建双向边,费用为运送每桶的花销,容量为最多可以运送的啤酒桶数。


#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#define maxn 2020#define maxm 220000#define INF 0x3f3f3f3fusing namespace std;int n, m;int outset, inset;struct node {int u, v, cap, flow, cost, next;};node edge[maxm];int head[maxn], cnt;int dist[maxn], vis[maxn];int per[maxn];void init(){cnt = 0;memset(head, -1, sizeof(head));}void add(int u, int v, int w, int c){node E1 = {u, v, w, 0, c, head[u]};edge[cnt] = E1;head[u] = cnt++;node E2 = {v, u, 0, 0, -c, head[v]};edge[cnt] = E2;head[v] = cnt++;}void getmap(){outset = 1;inset = n + 1;for(int i = 2; i <= n; ++i){int w;scanf("%d", &w);add(i, inset, INF, w);}while(m--){int a, b, c, w;scanf("%d%d%d%d", &a, &b, &c, &w);add(a, b, c, -w);add(b, a, c, -w);}}bool SPFA(int st, int ed){queue<int>q;memset(dist, -INF, sizeof(dist));memset(vis, 0, sizeof(vis));memset(per, -1, sizeof(per));dist[st] = 0;vis[st] = 1;q.push(st);while(!q.empty()){int u = q.front();q.pop();vis[u] = 0;for(int i = head[u]; i != -1 ; i = edge[i].next){node E = edge[i];if(dist[E.v] < dist[u] + E.cost && E.cap > E.flow){dist[E.v] = dist[u] + E.cost;per[E.v] = i;if(!vis[E.v]){vis[E.v] = 1;q.push(E.v);}}}}//注意,可以找到源点到汇点的最长路且最长路的值大于0时才增广 return per[ed] != -1 && dist[ed] > 0;//return per[ed] != -1;}void MCMF(int st, int ed, int &cost, int &flow){      flow = 0;      cost = 0;      while(SPFA(st, ed)){        int mins = INF;          for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){              mins = min(mins, edge[i].cap - edge[i].flow);          }        //增广         for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){              edge[i].flow += mins;              edge[i ^ 1].flow -= mins;              cost += edge[i].cost * mins;          }          flow += mins;      }  } int main (){int k = 0;while(scanf("%d%d", &n, &m) != EOF){init();getmap();int cost, flow;MCMF(outset, inset, cost, flow);printf("%d\n", cost);}return 0;}


0 0
原创粉丝点击