[SCOI2014]方伯伯运椰子,洛谷P3288,分数规划+判断负权环

版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83756897

正题

      题目链接点

      如果我们给一条边加1的流量,那么费用是不是多了a+d,给一条边减1的流量,那么费用多了b-d

      这两个都是挺明显的吧。

      考虑怎么保证流量平衡。

      设原边为(x_i,y_i,a_i,b_i,c_i,d_i)

      那么建两条边,(x_i,y_i,b_i+d_i),(y_i,x_i,a_i-d_i),现在改一个环就可以使得流量平衡。

      为什么?

      假设这个环先走了一段一类边,再走了一段二类边,然后再走了一段一类边。。。。。。

      那么在一类边的交点和二类边的交点的流量都是平衡的,二类边相当于反向边。画图看一下就明白了。

      好,那么这个环的边权和就是Y-X。但是题目要我们求max(\frac{X-Y}{k})

      k为环的大小。

      我们二分一个mid

      然后令这个东西大于mid,看看发生什么。

      \\\frac{X-Y}{k}>mid \\\to X-Y>mid*k \\\to mid*k+Y-X<0

      因为Y-X是环的边权和,所以\\mid*k+\sum_{i=1}^k w_i<0 \\\to \sum_{i=0}^k (w_i+mid)<0

      令新边权为w_i+mid,若能求出一个负环,那么说明答案比mid大,否则答案小于等于mid。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int n,m;
struct new_edge{
	int y,next;
	double c;
}s[60010];
int first[5010],len=0;
double dis[5010];
bool tf[5010];

void ins(int x,int y,double c){
	len++;
	s[len]=(new_edge){y,first[x],c};first[x]=len;
}

bool dfs(int x,double temp){
	tf[x]=true;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(dis[y]>dis[x]+s[i].c+temp){
			if(tf[y]) return true;
			dis[y]=dis[x]+s[i].c+temp;
			if(dfs(y,temp)) return true;
		}
	}
	return tf[x]=false;
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y,a,b,c,d;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d %d %d %d",&x,&y,&a,&b,&c,&d);
		ins(x,y,b+d);
		if(c) ins(y,x,a-d);
	}
	double l=0,r=1e7;
	while(r-l>=1e-3){
		for(int i=1;i<=n+2;i++) dis[i]=1e9,tf[i]=false;
		dis[n+1]=0;
		double mid=(l+r)/2;
		if(dfs(n+1,mid)) l=mid;
		else r=mid;
	}
	printf("%.2lf",l);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/83756897