1. 程式人生 > >[SCOI2014]方伯伯運椰子,洛谷P3288,分數規劃+判斷負權環

[SCOI2014]方伯伯運椰子,洛谷P3288,分數規劃+判斷負權環

正題

      題目連結點

      如果我們給一條邊加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);
}