ACM ICPC 2017 WF Problem J Son of Pipe Stream題解
阿新 • • 發佈:2020-12-14
ACM ICPC 2017 WF Problem J Son of Pipe Stream
一個神仙網路流題。
首先一個直觀的想法:可以列舉水的多少,然後讓flubber儘量多。
然後再慢慢調整當前的策略。
假設當前的候選答案為\(w,f\)。(表示水和flubber的數量)
若,當前在保證一個數不變的情況下可以增大另一個數,則這個一定不是最優解。
否則在增加一個數的同時另一個數會減小。可以發現一個數增加的數=另一個數減少的數。
所以兩個數的總和不變。
另一個發現,兩個加起來等於\(maxflow\)。
不然一定可以在保證\(s\)到其中一個源不退流而增廣另一個。
然後就可以得到可行的備選最優解\((w,f)\)
然後可以發現那個函式是單峰的。然後就直接實數三分就好了。(防止精度誤差,可以取\(\ln\))
code:
/* { ###################### # Author # # Gary # # 2020 # ###################### */ #include<bits/stdc++.h> #define rb(a,b,c) for(int a=b;a<=c;++a) #define rl(a,b,c) for(int a=b;a>=c;--a) #define LL long long #define IT iterator #define PB push_back #define II(a,b) make_pair(a,b) #define FIR first #define SEC second #define FREO freopen("check.out","w",stdout) #define rep(a,b) for(int a=0;a<b;++a) #define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()) #define random(a) rng()%a #define ALL(a) a.begin(),a.end() #define POB pop_back #define ff fflush(stdout) #define fastio ios::sync_with_stdio(false) #define check_min(a,b) a=min(a,b) #define check_max(a,b) a=max(a,b) using namespace std; //inline int read(){ // int x=0; // char ch=getchar(); // while(ch<'0'||ch>'9'){ // ch=getchar(); // } // while(ch>='0'&&ch<='9'){ // x=(x<<1)+(x<<3)+(ch^48); // ch=getchar(); // } // return x; //} const int INF=0x3f3f3f3f; typedef pair<int,int> mp; /*} */ const int GRAPH_SIZE=250 ; int pin[GRAPH_SIZE],dep[GRAPH_SIZE],s=0,t=GRAPH_SIZE-1; struct EDGE{ int u,v; double c; }; vector<EDGE> e; vector<int> each[GRAPH_SIZE]; bool bfs(){ queue<int> Q; Q.push(s); while(!Q.empty()){ int now=Q.front(); Q.pop(); for(auto it:each[now]){ int next=e[it].v; if(e[it].c) if(dep[next]>dep[now]+1){ dep[next]=dep[now]+1; Q.push(next); } } } return dep[t]!=INF; } double dfs(int now,double flow){ if(now==t){ return flow; } for(int & i= pin[now];i<each[now].size();i++){ int it=each[now][i]; if(e[it].c&&dep[e[it].v]==dep[now]+1){ double tmp; if(tmp=dfs(e[it].v,min(double(flow),e[it].c))){ e[it].c-=tmp; e[it^1].c+=tmp; return tmp; } } } return 0; } int Dinic(){ int max_flow=0; rep(i,GRAPH_SIZE) { dep[i]=INF; } dep[s]=0; while(bfs()){ rep(i,GRAPH_SIZE){ pin[i]=0; } double tmp; while(tmp=dfs(s,INF)){ max_flow+=tmp; } rep(i,GRAPH_SIZE){ dep[i]=INF; } dep[s]=0; } return max_flow; } void make_edge(int U,int V,double C){ EDGE tmp; tmp.u=U; tmp.v=V; tmp.c=C; e.PB(tmp); each[U].PB(e.size()-1); swap(tmp.u,tmp.v); tmp.c=0; e.PB(tmp); each[V].PB(e.size()-1); } void init(){ e.clear(); rep(i,GRAPH_SIZE){ each[i].clear(); } } int n,p; double v,a; double sum; double water[100000],flubber[100000]; map<mp,int> is; double calc(double x){ return log(pow(x,a))+log(pow(sum-x,1.0-a)); } void go(int now,double N,bool flub){ if(N==0) return; for(auto it:each[now]){ if(it&1) continue; if(e[it^1].c){ double& z=e[it^1].c; int id=is[II(e[it].u,e[it].v)]; double t=min(z,N); z-=t; N-=t; if(flub){ if(id<0){ id*=-1; flubber[id]-=t; go(e[it].v,t,flub); } else{ flubber[id]+=t; go(e[it].v,t,flub); } } else{ if(id<0){ id*=-1; water[id]-=t; go(e[it].v,t,flub); } else{ water[id]+=t; go(e[it].v,t,flub); } } } } } vector<pair<mp,int> > edges; void construct(double f){ init(); for(auto it:edges){ make_edge(it.FIR.SEC,it.FIR.FIR,it.SEC); make_edge(it.FIR.FIR,it.FIR.SEC,it.SEC); } make_edge(s,1,f); make_edge(s,2,sum-f); make_edge(3,t,INF); Dinic(); go(1,f,1); go(2,sum-f,0); } int main(){ scanf("%d%d",&n,&p); scanf("%lf%lf",&v,&a); rb(i,1,p){ int j,k,c; scanf("%d%d%d",&j,&k,&c); edges.PB(II(II(j,k),c)); is[II(j,k)]=i; is[II(k,j)]=-i; make_edge(j,k,c); make_edge(k,j,c); flubber[i]=water[i]=0.0; } make_edge(s,1,INF); make_edge(3,t,INF); Dinic(); make_edge(s,2,INF); Dinic(); int fm,wn,fn,wm; for(auto it:each[s]){ if(e[it].v==1){ fm=e[it^1].c; } else{ wn=e[it^1].c; } } init(); for(auto it:edges){ make_edge(it.FIR.SEC,it.FIR.FIR,it.SEC); make_edge(it.FIR.FIR,it.FIR.SEC,it.SEC); } make_edge(s,2,INF); make_edge(3,t,INF); Dinic(); make_edge(s,1,INF); Dinic(); for(auto it:each[s]){ if(e[it].v==1){ fn=e[it^1].c; } else{ wm=e[it^1].c; } } double rest=0.0; sum=fm+wn; double l,r; l=fn,r=fm; while(l+(1e-9)<r){ double mid=(l+r)/2.0; if(calc(mid)<calc(mid+(1e-9))){ l=mid+1e-9; } else{ r=mid; } } construct(l); rest=pow(l,a)*pow(sum-l,1.0-a); rb(i,1,p){ printf("%.10f %.10f\n",flubber[i]/v,water[i]); } printf("%.10f\n",rest*pow(v,-a)); return 0; }