• 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
    ",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
    ",pri*l);
    125     return 0;
    126 }
  • 相关阅读:
    [Leetcode] Regular Expression Matching
    [Leetcode] Edit Distance
    计算机科学论文写作3-表、图、例子和其他类似的元素的使用
    计算机科学论文写作2-搜寻、阅读和引用文献
    灰度图与彩图的双边滤波
    opencv6.1-imgproc图像处理模块之平滑与形态学操作
    opencv5-objdetect之级联分类器
    opencv4-highgui之视频的输入和输出以及滚动条
    计算机科学论文写作1-引言
    lecture11-hopfiled网络与玻尔兹曼机
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10238700.html
Copyright © 2020-2023  润新知