BZOJ 3130 SDOI2013 费用流
样例真是坑爹,给了和没给一样
显然对于Bob而言,只需要把P全部加到流量最大的那条边上显然对他是最有利的
问题就变成了求在最大流限制下使流量最大的边最小
二分之后将每条容量大于二分值的边减小到二分值并且跑网络流判断最大流是否改变即可
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<queue> #include<cmath> #define eps 1e-8 using namespace std; const int maxn=50010; const double oo=1e12; int n,m,p,S,T; int u,v,w; struct Edge{ int u,v; double w; }c[maxn]; int h[maxn],cnt=1; int cur[maxn]; struct edge{ int to,next; double w; }G[maxn<<1]; double ans=0.0,tmp; double L,R; int vis[maxn]; queue<int>Q; void read(int &num){ num=0;char ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void add(int x,int y,double z){ ++cnt; G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt; ++cnt; G[cnt].to=x;G[cnt].next=h[y];G[cnt].w=0;h[y]=cnt; } bool BFS(){ for(int i=S;i<=T;++i)vis[i]=-1; Q.push(S);vis[S]=1; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(G[i].w>0&&vis[v]==-1){ vis[v]=vis[u]+1; Q.push(v); } } }return vis[T]!=-1; } double DFS(int x,double f){ if(x==T||fabs(f)<eps)return f; double w,used=0; for(int i=cur[x];i;i=G[i].next){ if(vis[G[i].to]==vis[x]+1){ w=f-used; w=DFS(G[i].to,min(G[i].w,w)); G[i].w-=w;G[i^1].w+=w; if(G[i].w>0)cur[x]=i; used+=w;if(fabs(used-f)<eps)return used; } } if(fabs(used)<eps)vis[x]=-1; return used; } void dinic(){ ans=0.0; while(BFS()){ for(int i=S;i<=T;++i)cur[i]=h[i]; ans+=DFS(S,oo); }return; } bool check(double k){ memset(h,0,sizeof(h));cnt=1; for(int i=1;i<=m;++i){ if(c[i].w>k)add(c[i].u,c[i].v,k); else add(c[i].u,c[i].v,c[i].w); } dinic(); return fabs(ans-tmp)<eps; } int main(){ read(n);read(m);read(p); S=1;T=n; for(int i=1;i<=m;++i){ read(c[i].u);read(c[i].v); scanf("%lf",&c[i].w); add(c[i].u,c[i].v,c[i].w); } dinic(); printf("%d\n",(int)(ans+0.5)); L=0.0;R=ans;tmp=ans; while(R-L>eps){ double mid=(L+R)*0.5; if(check(mid))R=mid; else L=mid; }L=L*p; printf("%.4lf\n",L); return 0; }