给出一个运输网络,求该运输网络的最大流;
并且将运输网络的任意边赋上任意的单位流量权值v[i];
使∑v[i]=P,求一个最大流能使总费用最小;
n<=100,m<=1000;
题解:
第一问裸上Dinic;
第二问首先可以看出Bob一定会将所有的权值都赋给最大流量的边;
那么我们经应当使最大流量边最小;
然后二分。。。
二分的时候流量是实数。。实数网络流并不稳妥嘛;
要理性,不要愉悦!因为这道题精度限制不是十分精细,所以我们将所有的东西乘100000左右然后跑整数网络流;
然后我就被卡了。。从此我的Dinic模板多了一句话。。。
后面的点都出现了一种东西,就是一个二分完全图恰好被分为相邻两层,然后还没有流量。。。
之后每次都搜到它们都良妃一坨时间,所以我们要将不能流的点在这次DFS中删除;
if(ret==0) dis[x]=0;
然后就跑的飞快的AC了;
代码:
#include<queue> #include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #define N 110 #define M 11000 using namespace std; typedef long long ll; const ll K=100000; int to[M<<1],next[M<<1],head[N],ce=1; int val[M<<1]; ll flow[M<<1]; int n,dis[N]; queue<int>q; void add(int x,int y,int v) { to[++ce]=y; val[ce]=v; next[ce]=head[x]; head[x]=ce; to[++ce]=x; val[ce]=0; next[ce]=head[y]; head[y]=ce; } void clear(ll lim) { for(int i=2;i<=ce;i+=2) { flow[i]=min(lim,K*val[i]); flow[i^1]=0; } } bool BFS() { memset(dis,0,sizeof(dis)); dis[1]=1; q.push(1); int x,i; while(!q.empty()) { x=q.front(),q.pop(); for(i=head[x];i;i=next[i]) { if(flow[i]&&!dis[to[i]]) { dis[to[i]]=dis[x]+1; q.push(to[i]); } } } return dis[n]!=0; } ll dfs(int x,ll ma) { if(x==n) return ma; ll ret=0,temp; for(int i=head[x];i;i=next[i]) { if(flow[i]&&dis[to[i]]==dis[x]+1) { temp=dfs(to[i],min(ma-ret,flow[i])); flow[i]-=temp,flow[i^1]+=temp; ret+=temp; if(ma==ret) return ret; } } if(!ret) dis[x]=0; return ret; } ll Dinic(ll lim) { clear(lim); ll ans=0; while(BFS()) ans+=dfs(1,0x3f3f3f3f3f3f3f3fll); return ans; } int main() { int m,p,i,j,k,x,y,v,ma; ll l,r,mid,F; scanf("%d%d%d",&n,&m,&p); for(i=1,ma=0;i<=m;i++) { scanf("%d%d%d",&x,&y,&v); add(x,y,v); ma=max(ma,v); } F=Dinic(K*ma); printf("%lld\n",F/K); l=0,r=K*ma; while(l<=r) { mid=(l+r)/2; if(F==Dinic(mid)) r=mid-1; else l=mid+1; } printf("%.4lf\n",(double)l/K*p); return 0; }