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 15Sample Output
10 10.0000HINT
【樣例說明】
對於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]費用流