解题: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-6,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     for(int i=1;i<=n;i++)
20     {
21         dis[i]=inf,vis[i]=0;
22         inq[i]=true,qs.push(i);
23     }
24     while(!qs.empty())
25     {
26         int tn=qs.front(); 
27         inq[tn]=false,qs.pop();
28         for(int i=p[tn];i;i=noww[i])
29             if(dis[goal[i]]>dis[tn]+val[i]+x)
30             {
31                 dis[goal[i]]=dis[tn]+val[i]+x;
32                 if(!inq[goal[i]])
33                 {
34                     inq[goal[i]]=true,qs.push(goal[i]);
35                     if(++vis[goal[i]]>n) return false;
36                 }
37             }
38     }
39     return true;
40 }
41 int main()
42 {
43     scanf("%d%d",&n,&m),n+=2,r=1500;
44     for(int i=1;i<=m;i++)
45     {
46         scanf("%d%d%lf%lf%d%lf",&t1,&t2,&d1,&d2,&t3,&d3);
47         if((t1==n-1)||(t2==n-1)) continue;
48         link(t1,t2,d2+d3); if(t3) link(t2,t1,d1-d3); 
49     }
50     while(r-l>eps)
51     {
52         double mid=(l+r)/2;
53         if(check(mid)) r=mid;
54         else l=mid;
55     }
56     printf("%.2lf",r);
57     return 0;
58 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/9841452.html
今日推荐