「SCOI2014」方伯伯运椰子 解题报告

「SCOI2014」方伯伯运椰子

可以看出是分数规划

然后我们可以看出其实只需要改变1的流量就可以了,因为每次改变要保证流量守恒,必须流成一个环,在正负性确定的情况下,变几次是无所谓的。

然后按照套路,设

\[ans=\frac{X-Y}{k}\\ ans\times k =X-Y\\ ans\times k=-\sum w_i\\ \sum ans-w_i=0 \]

从第二部到第三步是把X和Y中的共同边都减掉了

\(w\)是根据扩容或者缩容建的边权为\(b+d,a-d\)的边权集合

注意一点,缩小容量必须\(c_i>0\)

然后发现环的边数就是\(k\),减过去就可以二分ans了


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
template <class T>
void read(T &x)
{
	x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=5010;
const int M=6010;
int n,m,u[N],v[N],a[N],b[N],c[N],d[N];
int head[N],to[M],Next[M],cnt;double edge[M];
void add(int u,int v,double w)
{
	to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
}
int used[N],vis[N],q[N*N],l,r;double dis[N];
bool spfa()
{
	for(int i=1;i<=n+2;i++) dis[i]=1e12;
	memset(vis,0,sizeof vis);
	memset(used,0,sizeof used);
	dis[q[l=r=1]=n+1]=0;
	while(l<=r)
	{
		int now=q[l++];
		used[now]=0;
		for(int v,i=head[now];i;i=Next[i])
			if(dis[v=to[i]]>dis[now]+edge[i])
			{
				dis[v]=dis[now]+edge[i];
				if((++vis[v])==n+2) return true;
				if(!used[v]) used[q[++r]=v]=1;
			}
	}
	return false;
}
bool check(double x)
{
	memset(head,0,sizeof head),cnt=0;
	for(int i=1;i<=m;i++)
	{
	    if(u[i]!=n+1)
		{
		    if(c[i]!=0) add(v[i],u[i],x+a[i]-d[i]);
		    add(u[i],v[i],x+b[i]+d[i]);
		}
        else
            add(u[i],v[i],0);
	}
	return spfa();
}
int main()
{
	read(n),read(m);
	double l=0,r=0;
	for(int i=1;i<=m;i++)
	{
		read(u[i]),read(v[i]),read(a[i]);
		read(b[i]),read(c[i]),read(d[i]);
		r+=1.0*c[i]*d[i];
	}
	while(l+1e-6<r)
	{
		double mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%.2lf\n",l);
	return 0;
}

2019.2.24

posted @ 2019-02-24 09:59  露迭月  阅读(227)  评论(0编辑  收藏  举报