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
",flubber[i]/v,water[i]);
}
printf("%.10f
",rest*pow(v,-a));
return 0;
}