【BZOJ3597】【SCOI2014】—方伯伯运椰子(分数规划)

传送门

显然流量不变的时候是最优的

考虑如果把一条边流量减一
花费是ada-d
扩大一次花费是b+db+d

想象一下,实际上最优操作就是对于2条起点终点相同的有向路径
压缩一条,扩大一条
把扩大看成正向,压缩看成反向的
实际上就变成了一个环

实际上我们现在就是要让一个环上的costlenfrac{sum -cost}{len}最小

因为有边的数量
考虑分数规划
costlenansfrac{sum -cost}{len}le ans
anslen+cost>=0ans*len+cost>=0

二分ansans
每条边加上midmid,看有没有负环,有则l=midl=mid,否则r=midr=mid

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res;
}
const int N=3005,M=5005;
const int inf=1e9;
const double eps=1e-6;
int str,des,adj[N],nxt[M<<1],to[M<<1],val[M<<1],vis[N],in[N],cnt,n,m;
double tp[M<<1],dis[M<<1];
inline void addedge(int u,int v,int w){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
inline bool spfa(){
	for(int i=1;i<=n+2;i++)dis[i]=inf;
	memset(vis,0,sizeof(vis));queue<int> q;
	dis[str]=0;in[str]=1;
	q.push(str);memset(in,0,sizeof(in));
	while(!q.empty()){
		int u=q.front();vis[u]=0,q.pop();
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(dis[v]>dis[u]+tp[e]){
				dis[v]=dis[u]+tp[e],in[v]=in[u]+1;
				if(in[v]>n+2)return 1;
				if(!vis[v]){
					vis[v]=1,q.push(v);
				}
			}
		}
	}
	return 0;
}
inline bool check(double k){
	for(int i=1;i<=cnt;i++)tp[i]=1.0*val[i]+k;
	return spfa();
}
int main(){
	n=read(),m=read();
	str=n+1,des=n+2;
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),a=read(),b=read(),c=read(),d=read();
		if(c!=0)addedge(v,u,a-d);
		addedge(u,v,b+d);
	}
	double l=-1e6,r=1e6;
	while(l+eps<r){
		double mid=(l+r)/2;
		if(check(mid))l=mid;
		else r=mid;
	}
	printf("%.2lf",l);
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145588.html