题解 CF653D 【Delivery Bears】

  • CF653D Delivery Bears

比较特别的网络流题目。

就是无脑乱搞,相信自己就过了!


  • Prelude

这个题上手就感觉太神必了,根本感觉不是网络流。该用网络流你不用,不用的你一个劲想。

因为众所周知题面告诉你一个算法的那这个题肯定不用这个算法(雾)。

为啥要说这个,因为这个题上手一看:每条边有容量,有流量,求最大流量,这不是网络流吗?

但是其实感觉很难做,因为要求的流量限制太多,很难直接做。于是我们需要转换思路了。


  • Solution

这个题也没啥建模,直接讲吧。

就是说,我们考虑到对于一个要求的重量的限制只是边上的限制 \(c_i\) 。如果我们知道货物的统一重量 \(d\) ,那么我们就只需要考虑一条边上经过的熊的个数上限 \(\displaystyle\lfloor \frac{c_i}{d}\rfloor\) 。这样有显然的好处:

  • 我们可以把运算转换成 int 类型的。
  • 这样方便判断每只熊是否能到达。

这样就可以直接判了,因为把每只熊看作 \(1\) 的流量,那么每只熊 \(1\rightarrow n\) 一路走下去如果不溢出必然有 \(x\) 的流量。所以只需要判断能否有 \(x\) 流量到达汇点 \(n\) 就这个 \(d\) 满足条件。

那么 \(d\) 怎么确定呢,都说到这份上了,还不想想二分答案?

上面那个显然是 check(mid) 的思路,所以直接做二分答案,上界 r 最多也就 \(1e6\)

一看 \(n\leq 50\) ,显然可以过。

最后的答案是总重量,所以是 \(x\times ans\)


  • Code

实现判断直接用 \(\texttt{Dinic}\) 跑最大流就可以了,超过 \(x\) 即是合法的。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
//#include<bits/stdc++.h>

#define ll long long
#define ull unsigned long long
#define INL inline
#define Re register

//Tosaka Rin Suki~
using namespace std;

INL int read()
{
	 int x=0;int w=1;
	 char ch=getchar();
	 while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	 if(ch=='-')w=-1,ch=getchar();
	 while(ch>='0'&&ch<='9')
	 {x=(x<<1)+(x<<3)+ch-48,ch=getchar();}
	 return x*w;
}

INL int mx(int a,int b){return a>b?a:b;}
INL int mn(int a,int b){return a<b?a:b;}

const int INF=1<<30,N=1005,M=1000005;

int n,m,x,S,T;

struct Rey
{
	int nxt,to,c;
}e[M];
int head[N],cnt;
int dis[N],cur[N];
int a[N],b[N],c[N];

INL void add_edge(int u,int v,int w)
{
	e[++cnt].nxt=head[u];
	e[cnt].to=v;
	e[cnt].c=w;
	head[u]=cnt;
}

INL void add_flow(int u,int v,int w)
{
	add_edge(u,v,w);
	add_edge(v,u,0);
}

INL bool bfs()
{
	queue <int> q;
	q.push(S);
	memset(dis,0,sizeof(dis));
	dis[S]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head[u];i;i=e[i].nxt)
		{
			int go=e[i].to;
			if(e[i].c>0&&!dis[go])
			{
				dis[go]=dis[u]+1;
				q.push(go);
				if(dis[T])return 1;
			}
		}
	}
	return dis[T]!=0;
}

INL int dfs(int x,int flow)
{
	if(x==T||!flow)return flow;
	int usd=0;
	for(int i=cur[x];i;i=e[i].nxt)
	{
        cur[x]=i;
		int go=e[i].to;
		if(e[i].c>0&&dis[go]==dis[x]+1)
		{
			int C=dfs(go,min(flow-usd,e[i].c));
			usd+=C;
			e[i].c-=C,e[i^1].c+=C;
			if(flow==0)return usd;
		}
	}
	if(!usd)dis[x]=0;
	return usd;
}

INL int Dinic()
{
	int fl=0;
	while(bfs())
	{
		memcpy(cur,head,sizeof(head));
		fl+=dfs(S,INF);
	}
	return fl;
}

INL bool check(double p)
{
	cnt=1;memset(head,0,sizeof(head));
	for(int i=1;i<=m;i++)
	{
        int x=min(c[i]/p,1e9);//p 有时候会莫名其妙的很小或者一些溢出问题,所以特判。
		add_flow(a[i],b[i],x);
	}
	return Dinic()>=x;
}

int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read(),m=read(),x=read();
	S=1,T=n;
	for(int i=1;i<=m;i++)
	{
		a[i]=read();b[i]=read(),c[i]=read();
	}
	double l=0,r=1e6;
	for(int i=0;i<80;i++)//因为是 double 所以直接暴力循环多次,在复杂度能承受范围以及误差范围内即可。
	{
		double mid=(l+r)/2;
		if(check(mid))l=mid;
		else r=mid;
	}
	printf("%.12lf\n",(double)l*x);
	return 0;
}
posted @ 2021-02-26 00:24  Reywmp  阅读(52)  评论(0编辑  收藏  举报