1. 程式人生 > >BZOJ 3130 [Sdoi2013]費用流

BZOJ 3130 [Sdoi2013]費用流

emp 流量 nbsp tdi hide nal for min ide

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]費用流