• 【 UVALive


    Description

    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 ∗ x
    2 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.


    Input
    There are several test cases.
    The first line of each case contains three integers, N, M and K. (1 ≤ N ≤ 100, 1 ≤ M ≤ 5000,
    0 ≤ K ≤ 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 ≤ ui
    , vi ≤ N,
    0 < ai ≤ 100, Ci ≤ 5)


    Output
    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(n<=100)座城市,由m(m<=5000)条单向道路相连。你希望从城市1运送k(0<=k<=100)单位货物到城市n。这些道路并不安全,有很多强盗,所以你决定雇保镖来保护你。每条道路都有一个危险系数ai(0<ai<=100),如果你带着x个单位货物通过,需要给保镖aix^2元钱才能保证你的安全(这是合理的,因为带在身边的货物越多越不安全)。另外,每条路上还有一个容量限制Ci(Ci<=5),表示最多只能带Ci个单位的货物通过。注意,货物不能拆开,因此在通过每条边时,身上的货物数量必须是整数。

    【分析】

      此题要拆边。(容量较小)

      对于一个费用系数为a,容量为5的边拆成5条容量为1,费用依次为1a,3a,5a,7a,9a的边。

      因为求的是最小费用流,如果这条弧的流量为1,走的肯定是1a;如果流量为2,走的肯定是1a,3a这两条,如果流量为3,走的肯定是1a,3a,5a……不难验证,不管流量是1~5之间的哪一个,相应流量选取的边的费用之和恰好就是未拆边是的相应费用。

      这样问题就转化成普通的最小费用最大流问题了。(当流量到达k即可break)

      费用流大概是这样做的:

      每次找费用最小的增广路走,走到走不完为止。所以最终ans是最大流前提下最小费用。

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 110
      9 #define Maxm 5100
     10 #define INF 0xfffffff
     11 
     12 int n,m,k;
     13 
     14 struct node
     15 {
     16     int x,y,f,c,o,next;
     17 }t[Maxm*10];int len;
     18 int first[Maxn];
     19 int flow[Maxn],dis[Maxn],pre[Maxn];
     20 bool inq[Maxn];
     21 
     22 int mymin(int x,int y) {return x<y?x:y;}
     23 
     24 void ins(int x,int y,int f,int c)
     25 {
     26     t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c;
     27     t[len].next=first[x];first[x]=len;t[len].o=len+1;
     28     t[++len].x=y;t[len].y=x;t[len].f=0;t[len].c=-c;
     29     t[len].next=first[y];first[y]=len;t[len].o=len-1;
     30 }
     31 
     32 queue<int > q;
     33 bool BFS(int f1,int f2)
     34 {
     35     while(!q.empty()) q.pop();
     36     memset(pre,-1,sizeof(pre));
     37     memset(inq,0,sizeof(inq));
     38     memset(dis,63,sizeof(dis));
     39     pre[f1]=0;flow[f1]=INF;inq[f1]=1;
     40     dis[f1]=0;q.push(f1);
     41     while(!q.empty())
     42     {
     43         int x=q.front(),y,i;
     44         for(i=first[x];i;i=t[i].next) if(t[i].f>0)
     45         {
     46             y=t[i].y;
     47             if(dis[y]>dis[x]+t[i].c)
     48             {
     49                 pre[y]=i;
     50                 dis[y]=dis[x]+t[i].c;
     51                 flow[y]=mymin(t[i].f,flow[x]);
     52                 if(!inq[y]) {q.push(y);inq[y]=1;}
     53             }
     54         }
     55         q.pop();inq[x]=0;
     56     }
     57     if(pre[f2]==-1) return 0;
     58     return flow[f2];
     59 }
     60 
     61 void max_flow(int x,int y)
     62 {
     63     int a,sum=0,h=0;
     64     bool ok=0;
     65     while(a=BFS(x,y))
     66     {
     67         int now=y;sum+=a*dis[y];
     68         h+=a;
     69         while(now!=x)
     70         {
     71             t[pre[now]].f-=a;
     72             t[t[pre[now]].o].f+=a;
     73             now=t[pre[now]].x;
     74         }
     75         if(h>=k) break;
     76     }
     77     if(h<k) printf("-1
    ");
     78     else printf("%d
    ",sum);
     79 }
     80 
     81 int main()
     82 {
     83     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
     84     {
     85         len=0;
     86         memset(first,0,sizeof(first));
     87         for(int i=1;i<=m;i++)
     88         {
     89             int x,y,z,kk,now=0;
     90             scanf("%d%d%d%d",&x,&y,&z,&kk);
     91             for(int i=1;i<=kk;i++)
     92             {
     93                 ins(x,y,1,z*(i*i-now));
     94                 now+=i*i-now;
     95             }
     96         }
     97         max_flow(1,n);
     98     }
     99     return 0;
    100 }
    [LA5095]

    2016-05-23 13:39:41

  • 相关阅读:
    DOM1
    js操作符
    五种基本数据类型知识点梳理
    自动刷新服务:nodemon
    The language server needs at least PHP 7.1 installed. Version found: 7.0.10
    jQuery插件
    Wampserver64 报错:无法启动此程序,因为计算机中丢失 MSVCR110.dll。尝试重新安装该程序以解决此问题。
    return true 与 return false的妙用——jQuery
    jQuery真伪数组转换
    【分享】精简Linux的源代码
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5519666.html
Copyright © 2020-2023  润新知