• 【拆边最小费用流】【Asia Harbin 2010/2011】【Transportation】


    【题目描述】There are N cities, and M directed roads connecting them. Now you want to transport K  units of goods from city 1 to city N. There are many robbers on the road, so you must  be very careful. The more goods you carry, the more dangerous it is. To be more specific,  for each road i, there is a coefficient ai. If you want to carry x units of goods along  this road, you should pay ai * x2 dollars to hire guards to protect your goods. And what's  worse, for each road i, there is an upper bound Ci, which means that you cannot transport  more than Ci units of goods along this road. Please note you can only carry integral unit  of goods along each road.

    You should find out the minimum cost to transport all the goods safely.

    There are several test cases. The first line of each case contains three integers, N, M and K. (1$ \le$N$ \le$100, 1$ \le$M$ \le$5000, 0$ \le$K$ \le$100). Then M lines followed, each  contains four integers (ui, vi, ai, Ci), indicating there is a directed road  from city ui to vi, whose coefficient is ai and upper bound is Ci. (1$ \le$ui, vi$ \le$N, 0 < ai$ \le$100, Ci$ \le$5)

    Output one line for each test case, indicating the minimum cost. If it is impossible to  transport all the K units of goods, output `-1'.

    Sample Input

    2 1 2 
    1 2 1 2 
    2 1 2 
    1 2 1 1 
    2 2 2 
    1 2 1 2 
    1 2 2 2
    

    Sample Output

    4 
    -1 
    3
    

    【中文大意】N个点M条有向边的图,希望从点1运送K单位货物到点N,每条边有运送货物的容量,以及运送货物的费用。值得小心的是,费用的计算方式改变了,不再是流量*费用,而是流量^2*费用。

    【题目分析】由于费用的计算方式改变了,变成流量^2*费用,因此倘若仍按最小费用流的SPFA增广,就会发现某条费用小的边因为流量增广的比较多,而导致总费用不如分流到其它费用稍大的边上面。

          注意一个至关重要的条件,Ci<=5,上述情况的本质问题在于费用随流量呈二次方增长,如:当流量为1的时候,费用小的边必然先通过,但是当流量为增至2时候,这条边本质等于是2条流量为1的边,费用分别为1和3,这样也就能很明显的看出,拆边之后SPFA增广就可以进行了。

          想到将某条边的容量全部拆成容量为1的边,费用为1,3,5,7,9(最多为9),剩下的是跑最小费用流。可以增加一个点作为源点S,然后S->1连一条费用为0容量为K的边。顺便记录一下最大流的值,最后判断最大流是否等于K,是则输出最小费用,否则输出-1。

    【代码如下】

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <climits>
      4 #include <vector>
      5 #include <deque>
      6 #include <algorithm>
      7 
      8 #define FILE_IO
      9 
     10 using namespace std;
     11 
     12 const int Maxn = 101, INF = INT_MAX;
     13 
     14 struct edge
     15 {
     16     int v, c, w;
     17     edge* next, * op;
     18     edge(int _v, int _c, int _w, edge* _next) : v(_v), c(_c), w(_w), next(_next) {}
     19 }* E[Maxn], * PE[Maxn];
     20 
     21 bool hash[Maxn];
     22 int S, T, Maxflow, Costflow, P[Maxn], N, M, K;
     23 vector <int> Dist;
     24 deque <int> Q;
     25 
     26 
     27 void Clear()
     28 {
     29     for (int i = 0; i <= T; i ++)
     30     {
     31         E[i] = NULL; PE[i] = NULL; P[i] = 0;
     32     }
     33 }
     34 
     35 void Augment()
     36 {
     37     int add = INF;
     38     for (int i = T; i != S; i = P[i])
     39     {
     40         add = min(add, PE[i] -> c);
     41     }
     42     Maxflow += add;
     43     for (int i = T; i != S; i = P[i])
     44     {
     45         PE[i] -> c -= add;
     46         PE[i] -> op -> c += add;
     47         Costflow += add * add * PE[i] -> w;
     48     }
     49 }
     50 
     51 bool Label()
     52 {
     53     Dist.assign(T + 1, INF); Dist[S] = 0;
     54     Q.push_back(S);
     55     while (Q.size())
     56     {
     57         int i = Q.front(); Q.pop_front(); hash[i] = false;
     58         for (edge* j = E[i]; j; j = j -> next)
     59         {
     60             int v = j -> v;
     61             if (j -> c && Dist[i] + j -> w < Dist[v])
     62             {
     63                 Dist[v] = Dist[i] + j -> w;
     64                 P[v] = i; PE[v] = j;
     65                 if (!hash[v])
     66                 {
     67                     hash[v] = true;
     68                     Q.push_back(v);
     69                 }
     70             }
     71         }
     72     }
     73     return Dist[T] != INF;
     74 }
     75 
     76 void SPFAFlow()
     77 {
     78     Maxflow = Costflow = 0;
     79     while (Label()) Augment();
     80 }
     81 
     82 inline void edgeAdd(int x, int y, int c, int w)
     83 {
     84     E[x] = new edge(y, c, w, E[x]);
     85     E[y] = new edge(x, 0, -w, E[y]);
     86     E[x] -> op = E[y]; E[y] -> op = E[x];
     87 }
     88 
     89 void Init()
     90 {
     91     S = 0; T = N;
     92     for (int i = 1; i <= M; i ++)
     93     {
     94         int x, y, c, w; cin >> x >> y >> w >> c;
     95         for (int j = 1; j <= c; j ++) edgeAdd(x, y, 1, w * (j * 2 - 1));
     96     }
     97     edgeAdd(0, 1, K, 0);
     98 }
     99 
    100 int main()
    101 {
    102     #ifdef FILE_IO
    103     //freopen("test.in", "r", stdin);
    104     #endif // FILE_IO
    105     while (cin >> N >> M >> K)
    106     {
    107         Init();
    108         SPFAFlow();
    109         if (Maxflow == K) cout << Costflow << endl;
    110         else cout << -1 << endl;
    111         Clear();
    112     }
    113     return 0;
    114 }
  • 相关阅读:
    VTK初学一,b_PolyVertex多个图形点的绘制
    VTK初学一,a_Vertex图形点的绘制
    Python基础学习之集合
    Apache
    NTP时间同步服务和DNS服务
    NFS服务及DHCPD服务
    samba服务及vsftpd服务
    Linux rpm和yum软件管理
    Linux网络技术管理及进程管理
    Linux RAID磁盘阵列
  • 原文地址:https://www.cnblogs.com/GXZC/p/2840446.html
Copyright © 2020-2023  润新知