zoukankan      html  css  js  c++  java
  • 解题:SCOI 2014 方伯伯运椰子

    题面

    很有趣的一道题,看起来是个神奇网络流,其实我们只要知道网络的一些性质就可以做这道题了

    因为题目要求流量守恒,所以我们其实是在网络中搬运流量,最终使得总费用减小,具体来说我们可以直接把这种“搬运”的关系建出来:

    对于一条从$u$到$v$的边,从$u$向$v$连一条$b+d$的边,如果其上限不为零,再从$v$向$u$连一条$a-d$的边

    那么得到的这张新图其实是描述了图中的费用流,一个合法的搬运方案就是一个环(转了一圈保证流量还是守恒的),然后有一个叫做消圈定理的东西:

    消圈定理:残量网络里如果存在负费用环,那么当前流不是最小费用流。因为通过增加残量网络负权边的流量,减少正权边的流量,一定能得到另一个更优的可行流。

    于是就判负环吧=。=

     1 #include<queue> 
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int N=5005,M=3005;
     7 const double eps=1e-4,inf=1e12;
     8 int n,m,t1,t2,t3,cnt,last,from;
     9 double val[2*M+N],dis[N],d1,d2,d3,l,r; 
    10 int p[N],noww[2*M+N],goal[2*M+N],inq[N],vis[N];
    11 queue<int> qs;
    12 void link(int f,int t,double v)
    13 {
    14     noww[++cnt]=p[f],p[f]=cnt;
    15     goal[cnt]=t,val[cnt]=v;
    16 }
    17 bool check(double x)
    18 {
    19     memset(vis,0,sizeof vis);
    20     for(int i=1;i<=n;i++) dis[i]=inf;
    21     dis[from]=0,inq[from]=true,qs.push(from);
    22     while(!qs.empty())
    23     {
    24         int tn=qs.front(); 
    25         inq[tn]=false,qs.pop();
    26         for(int i=p[tn];i;i=noww[i])
    27             if(dis[goal[i]]>dis[tn]+val[i]+x)
    28             {
    29                 dis[goal[i]]=dis[tn]+val[i]+x;
    30                 if(!inq[goal[i]])
    31                 {
    32                     inq[goal[i]]=true,qs.push(goal[i]);
    33                     if(++vis[goal[i]]>n) return false;
    34                 }
    35             }
    36     }
    37     return true;
    38 }
    39 int main()
    40 {
    41     scanf("%d%d",&n,&m),n+=2,r=1500;
    42     for(int i=1;i<=m;i++)
    43     {
    44         scanf("%d%d%lf%lf%d%lf",&t1,&t2,&d1,&d2,&t3,&d3);
    45         if(t1==n-1) {from=t2; continue;}
    46         if(t2==n-1) {from=t1; continue;}
    47         link(t1,t2,d2+d3); if(t3) link(t2,t1,d1-d3); 
    48     }
    49     while(r-l>eps)
    50     {
    51         double mid=(l+r)/2;
    52         if(check(mid)) r=mid;
    53         else l=mid;
    54     }
    55     printf("%.2lf",r);
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    模块的搜索路径
    循环导入问题
    模块的四种形式
    匿名函数
    面向过程编程
    内置函数
    名称空间和作用域
    函数嵌套
    函数对象
    可变长参数
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9841452.html
Copyright © 2011-2022 走看看