1. 程式人生 > 實用技巧 >ACM ICPC 2017 WF Problem J Son of Pipe Stream題解

ACM ICPC 2017 WF Problem J Son of Pipe Stream題解

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