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
1 2 10
2 3 15
Sample Output
10
10.0000
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 }