有n个城市,有m条有向边,对应有x个熊搬东西。
接下来m条有向边的输入三个元素,表示起点终点以及这条路径上总共最多可以运送多少货物。
问需要每只熊都搬动相同重量的东西从点1到点n,问最多能够送过去多少重量的货物。
思路:
1、经典最大流模型,首先对应其解我们可以通过枚举的方式来找到,再分析其单调性(重量越低,越能送到),我们还可以使用二分查找的方式来枚举其解,使得算法更加优化。
2、对应枚举出的当前值mid,表示其能够送出的总重量。
那么每一只熊需要送的重量就是mid/x;
那么建图方式如下:
①建立源点,将源点连入节点1,权值设定为x。
②建立汇点,将节点n连入汇点,权值设定为x。
③对应m条有向边,加入网络中,权值设定为w/(mid/x)。
那么对应当前二分值mid,如果跑一遍最大流得到的值是满流(maxflow==x)那么当前mid值就是一个可行解。
3、注意精度。注意数据范围,当我们枚举到的当前值mid/x比较小,然而w却比较大的时候,数据会使用到long long。
注意精度和数据范围即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
#define ll __int64
struct node
{
ll from;
ll to;
ll w;
ll next;
}e[120000];
#define eps 1e-8
ll n,m,x,cont,ss,tt;
ll divv[2000];
ll head[2000];
ll cur[2000];
ll bian[2000][4];
void add(ll from,ll to,ll w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void getmap(double mid)
{
ss=n+1;
tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
add(ss,1,x);
add(1,ss,0);
add(n,tt,x);
add(tt,n,0);
for(ll i=0;i<m;i++)
{
double w=bian[i][2];
add(bian[i][0],bian[i][1],(ll)(w/mid));
add(bian[i][1],bian[i][0],0);
}
}
ll makedivv()
{
memset(divv,0,sizeof(divv));
divv[ss]=1;
queue<ll >s;
s.push(ss);
while(!s.empty())
{
ll u=s.front();
if(u==tt)return 1;
s.pop();
for(ll i=head[u];i!=-1;i=e[i].next)
{
ll v=e[i].to;
ll w=e[i].w;
if(w&&divv[v]==0)
{
divv[v]=divv[u]+1;
s.push(v);
}
}
}
return 0;
}
ll Dfs(ll u,ll maxflow,ll tt)
{
if(u==tt)return maxflow;
ll ret=0;
for(ll &i=cur[u];i!=-1;i=e[i].next)
{
ll v=e[i].to;
ll w=e[i].w;
if(w&&divv[v]==divv[u]+1)
{
ll f=Dfs(v,min(maxflow-ret,w),tt);
e[i].w-=f;
e[i^1].w+=f;
ret+=f;
if(ret==maxflow)return ret;
}
}
return ret;
}
ll Slove(double mid)
{
mid=mid/x;
getmap(mid);
ll ans=0;
while(makedivv()==1)
{
memcpy(cur,head,sizeof(head));
ans+=Dfs(ss,0x3f3f3f3f,tt);
}
if(ans==x)return 1;
else return 0;
}
int main()
{
while(~scanf("%I64d%I64d%I64d",&n,&m,&x))
{
double maxn;
for(ll i=0;i<m;i++)
{
scanf("%I64d%I64d%I64d",&bian[i][0],&bian[i][1],&bian[i][2]);
double w=bian[i][2];
maxn=max(w,maxn);
}
double mid;
double ans=-1;
double l=0;
double r=10000000000;
while(r-l>=eps)
{
mid=(l+r)/2;
if(Slove(mid)==1)
{
ans=mid;
l=mid;
}
else
{
r=mid;
}
}
printf("%lf\n",ans);
}
}