题意:
给出一个运输网络,求该运输网络的最大流;
并且将运输网络的任意边赋上任意的单位流量权值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;
}