1. 程式人生 > >BZOJ3130: [Sdoi2013]費用流(二分,最大流)

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\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 }