BZOJ 3130 [Sdoi2013]费用流

Posted Doggu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3130 [Sdoi2013]费用流相关的知识,希望对你有一定的参考价值。

3130: [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

HINT

【样例说明】

对于Alice,最大流的方案是固定的。两条边的实际流量都为10。

对于Bob,给第一条边分配0.5的费用,第二条边分配0.5的费用。

总费用 为:10*0.5+10*0.5=10。可以证明不存在总费用更大的分配方案。

【数据规模和约定】

对于20%的测试数据:所有有向边的最大流量都是1。

对于100%的测试数据:N < = 100,M < =  1000。

对于l00%的测试数据:所有点的编号在I..N范围内。1 < = 每条边的最大流量 < =  50000。1 < = P < = 10。给定运输网络中不会有起点和终点相同的边。

 

  长春亚泰(National Night)说,这道题写着费用流的题目,穿着博弈论的外衣,还请出来了Alice和Bob两哥们儿,试图用样例说明卡你智商,最终发现就只是考你反应的题。

  很容易发现,最大流的值是固定的,p值是一定的,但对于Alice的方案,Bob最后的总费用就只能是图中流量最大的弧的流量*所谓的p值。所以Alice就需要让图中流量最大的弧的流量最小。

  怎么办呢?长春亚泰又说:

  显然需要二分来解决。

  但我当时并没有想到,试图真的去用费用流那套理论来解决问题,我好菜啊。怎么办呢?长春亚泰又说:

  每次让每条边的流量上限与二分值取min判定一下这样能否流出最大流即可

  啊啊啊啊啊。于是这样,似乎就可以交了。于是我WA了。怎么回事!!!最后发现:

  注意小数网络流的精度问题

  为什么啊?因为如果要相对均分,那么一均,小数就出来了。EPS,EPS,EPS,能开double全开double,AC!

  

技术分享
 1 /************************************************************** 
 2     Problem: 3130 
 3     User: Doggu 
 4     Language: C++ 
 5     Result: Accepted 
 6     Time:84 ms 
 7     Memory:872 kb 
 8 ****************************************************************/
 9   
10 #include <cstdio> 
11 #include <cstring> 
12 #include <algorithm> 
13 using namespace std; 
14 template<class T>inline void readin(T &res) { 
15     static char ch; 
16     while((ch=getchar())<0||ch>9); 
17     res=ch-48;while((ch=getchar())>=0&&ch<=9)res=(res<<1)+(res<<3)+ch-48; 
18 } 
19   
20 const int N = 110; 
21 const int M = 2010; 
22 const double eps = 1e-6; 
23 struct Edge{int v,upre;double cap,flow;}g[M]; 
24 int head[N], ne=-1; 
25 inline void adde(int u,int v,double cap) { 
26     g[++ne]=(Edge){v,head[u],cap,0},head[u]=ne; 
27     g[++ne]=(Edge){u,head[v],0,0},head[v]=ne; 
28 } 
29   
30 int n, m, s, t, p, ok; 
31 int q[N], front, rear, d[N], cur[N]; 
32 bool BFS(double Bound) { 
33     memset(d, 0,sizeof(d)); 
34     front=rear=0;d[s]=1;q[rear++]=s; 
35     while(front!=rear) { 
36         int u=q[front++]; 
37         for( int i = head[u]; i!=-1; i = g[i].upre ) { 
38             int v=g[i].v;if(ok) g[i].flow=0,g[i^1].flow=0; 
39             if(!d[v]&&min(Bound,g[i].cap)>g[i].flow+eps) d[v]=d[u]+1,q[rear++]=v; 
40         } 
41     } 
42     ok=0; 
43     return d[t]>0?1:0; 
44 } 
45 double DFS(int u,double a,double Bound) { 
46     if(u==t||a==0) return a; 
47     double flow=0, f; 
48     for( int &i = cur[u]; i!=-1; i = g[i].upre ) { 
49         int v=g[i].v; 
50         if(d[v]==d[u]+1&&(f=DFS(v,min(a,min(Bound,g[i].cap)-g[i].flow),Bound))>eps) { 
51             flow+=f;a-=f;g[i].flow+=f;g[i^1].flow-=f; 
52             if(a==0) return flow; 
53         } 
54     } 
55     if(!flow) d[u]=0; 
56     return flow; 
57 } 
58 double maxflow(double Bound) { 
59     double flow=0; 
60     while(BFS(Bound)) { 
61         memcpy(cur, head,sizeof(head)); 
62         flow+=DFS(s,0x3f3f3f3f,Bound); 
63     } 
64     return flow; 
65 } 
66   
67 int main() { 
68     memset(head, -1,sizeof(head)); 
69     readin(n);readin(m);readin(p); 
70     double CMP, lf=0, rg=0; 
71     for( int i = 1; i <= m; i++ ) { 
72         int u, v;double cap; 
73         readin(u);readin(v);scanf("%lf",&cap); 
74         rg=max(rg,cap); 
75         adde(u,v,cap); 
76     } 
77     s=1;t=n; 
78     CMP=maxflow(0x3f3f3f3f); 
79     while(lf+eps<rg) { 
80         double mid=(lf+rg)/2; 
81         ok=1;double tmp=maxflow(mid); 
82         if(tmp<CMP) lf=mid; 
83         else rg=mid; 
84     } 
85     printf("%.lf\n%.4lf\n",CMP,lf*p); 
86     return 0; 
87 }
dinic+二分+eps

 

 

 

  

以上是关于BZOJ 3130 [Sdoi2013]费用流的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3130 Sdoi2013 费用流

BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

bzoj 3130: [Sdoi2013]费用流

BZOJ 3130 [Sdoi2013]费用流

Bzoj3130 [Sdoi2013]费用流

bzoj 3130 [Sdoi2013]费用流(二分,最大流)