BZOJ3130: [Sdoi2013]费用流(二分,最大流)

Description

 Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识。
    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量。一个合法的网络流方案必须满足:(1)每条边的实际流量都不超过其最大流量且非负;(2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量;而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量。最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案。

  上图表示了一个最大流问题。对于每条边,右边的数代表该边的最大流量,左边的数代表在最优解中,该边的实际流量。需要注意到,一个最大流问题的解可能不是唯一的。    对于一张给定的运输网络,Alice先确定一个最大流,如果有多种解,Alice可以任选一种;之后Bob在每条边上分配单位花费(单位花费必须是非负实数),要求所有边的单位花费之和等于P。总费用等于每一条边的实际流量乘以该边的单位花费。需要注意到,Bob在分配单位花费之前,已经知道Alice所给出的最大流方案。现茌Alice希望总费用尽量小,而Bob希望总费用尽量大。我们想知道,如果两个人都执行最优策略,最大流的值和总费用分别为多少。

Input

    第一行三个整数N,M,P。N表示给定运输网络中节点的数量,M表示有向边的数量,P的含义见问题描述部分。为了简化问题,我们假设源点S是点1,汇点T是点N。
    接下来M行,每行三个整数A,B,C,表示有一条从点A到点B的有向边,其最大流量是C。

Output

第一行一个整数,表示最大流的值。
第二行一个实数,表示总费用。建议选手输出四位以上小数。

Sample Input

3 2 1
1 2 10
2 3 15

Sample Output

10
10.0000
解题思路:
第一问不说了。
Alice、Bob都上了,那不是裸的博弈论吗?
第二问,根据博弈论贪心Bob会将全部的花费都花在最大边上,也就是最大流量上。
根据贪心性质,减小边容量并不会增大最大流(废话)
所以只需要二分最大花费的大小,然后全图限制流量不超过最大流量。
这时只需要再跑一遍Dinic检查最大流是否变化就好了。
代码:
  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const double oo=(double)(0x3f3f3f3f);
  6 const double eps=1e-7;
  7 struct pnt{
  8     int hd;
  9     int lyr;
 10     int now;
 11 }p[100000];
 12 struct ent{
 13     int twd;
 14     int lst;
 15     double vls;
 16     double his;
 17 }e[1000000];
 18 int cnt;
 19 int n,m;
 20 int s,t;
 21 std::queue<int>Q;
 22 void ade(int f,int t,double v)
 23 {
 24     cnt++;
 25     e[cnt].twd=t;
 26     e[cnt].vls=v;
 27     e[cnt].his=v;
 28     e[cnt].lst=p[f].hd;
 29     p[f].hd=cnt;
 30     return ;
 31 }
 32 bool Bfs(void)
 33 {
 34     while(!Q.empty())Q.pop();
 35     for(int i=1;i<=t;i++)
 36         p[i].lyr=0;
 37     p[s].lyr=1;
 38     Q.push(s);
 39     while(!Q.empty())
 40     {
 41         int x=Q.front();
 42         Q.pop();
 43         for(int i=p[x].hd;i;i=e[i].lst)
 44         {
 45             int to=e[i].twd;
 46             if(p[to].lyr==0&&e[i].vls>eps)
 47             {
 48                 p[to].lyr=p[x].lyr+1;
 49                 if(to==t)
 50                     return true;
 51                 Q.push(to);
 52             }
 53         }
 54     }
 55     return false;
 56 }
 57 double Dfs(int x,double fll)
 58 {
 59     if(x==t)
 60         return fll;
 61     for(int& i=p[x].now;i;i=e[i].lst)
 62     {
 63         int to=e[i].twd;
 64         if(p[to].lyr==p[x].lyr+1&&e[i].vls>eps)
 65         {
 66             double ans=Dfs(to,std::min(fll,e[i].vls));
 67             if(ans>eps)
 68             {
 69                 e[i].vls-=ans;
 70                 e[((i-1)^1)+1].vls+=ans;
 71                 return ans;
 72             }
 73         }
 74     }
 75     return 0.00;
 76 }
 77 double Dinic(void)
 78 {
 79     double ans=0.00;
 80     while(Bfs())
 81     {
 82         for(int i=1;i<=t;i++)
 83             p[i].now=p[i].hd;
 84         double dlt;
 85         while((dlt=Dfs(s,oo))>eps)
 86             ans+=dlt;
 87     }
 88     return ans;
 89 }
 90 bool check(double maxflow,double x)
 91 {
 92     for(int i=1;i<=cnt;i++)
 93         e[i].vls=std::min(e[i].his,x);
 94     double ans=Dinic();
 95     return maxflow-ans<=eps;
 96 }
 97 int main()
 98 {
 99 //    freopen("a.in","r",stdin);
100     double pri;
101     scanf("%d%d",&n,&m);
102     s=1,t=n;
103     scanf("%lf",&pri);
104     for(int i=1;i<=m;i++)
105     {
106         int a,b;
107         double c;
108         scanf("%d%d",&a,&b);
109         scanf("%lf",&c);
110         ade(a,b,c);
111         ade(b,a,0);
112     }
113     double maxflow=Dinic();
114     printf("%.0lf\n",maxflow);
115     double l=0.00,r=oo;
116     while(r-l>eps)
117     {
118         double mid=(l+r)/2.00;
119         if(check(maxflow,mid))
120             r=mid;
121         else
122             l=mid;
123     }
124     printf("%.4lf\n",pri*l);
125     return 0;
126 }
posted @ 2019-01-08 14:10  Unstoppable728  阅读(210)  评论(0编辑  收藏  举报