BZOJ3597: [Scoi2014]方伯伯运椰子

Description

 

Input

 第一行包含二个整数N,M

接下来M行代表M条边,表示这个交通网络
每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di
接下来一行包含一条边,表示连接起点的边

Output

一个浮点数,保留二位小数。表示答案,数据保证答案大于0

Sample Input

5 10
1 5 13 13 0 412
2 5 30 18 396 148
1 5 33 31 0 39
4 5 22 4 0 786
4 5 13 32 0 561
4 5 3 48 0 460
2 5 32 47 604 258
5 7 44 37 75 164
5 7 34 50 925 441
6 2 26 38 1000 22

Sample Output

103.00

HINT

 1<=N<=5000


0<=M<=3000

1<=Ui,Vi<=N+2

0<=Ai,Bi<=500

0<=Ci<=10000

0<=Di<=1000

Source

显然答案满足二分性,思考怎么check
如果存在一种费用更小的流法,那么一定会形成一个环
例如
    +1->+1
↗           ↘
↘           ↗
    -1->-1
这样就流量平衡,那么我们把增容的边弄成正向,减容的边弄成反向,那么一种最优的做法一定是一个负权环
所有边减去二分的答案后 就是喜闻乐见的找负环了
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 5200;
const int MAXM = 6666;
const double eps = 1e-3;

double l, r, ans;

int n, m, cnt, head[MAXN];

struct edge
{
	int to, nxt;
	double val;
}e[MAXM];

inline void addedge(int x, int y, double w) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; e[ cnt ].val = w; }

double dis[MAXN];

bool vis[MAXN];

inline bool dfs(int x)
{
	vis[ x ] = 1;
	for( int i = head[ x ] ; i ; i = e[ i ].nxt )
		if( dis[ e[ i ].to ] > dis[ x ] + e[ i ].val )
		{
			dis[ e[ i ].to ] = dis[ x ] + e[ i ].val;
			if( vis[ e[ i ].to ] ) return true;
			if( dfs( e[ i ].to ) ) return true;
		}
	vis[ x ] = 0;
	return false;
}

inline bool chk()
{
	for( int i = 1 ; i <= n ; i++ ) dis[ i ] = 0, vis[ i ] = 0;
	for( int i = 1 ; i <= n ; i++ ) if( dfs( i ) ) return true;
	return false;
}

int main()
{
	scanf( "%d%d", &n, &m );
	n += 2;
	for( int i = 1 ; i <= m ; i++ )
	{
		int u, v, a, b, c, d;
		scanf( "%d%d%d%d%d%d", &u, &v, &a, &b, &c, &d );
		addedge( u, v, b + d );
		if( c ) addedge( v, u, a - d );
	}
	l = 0, r = 1e9;
	while( r - l > eps )
	{
		double mid = ( l + r ) / 2.0;
		for( int i = 1 ; i <= cnt ; i++ ) e[ i ].val += mid;
		if( chk() ) l = mid;
		else r = mid;
		for( int i = 1 ; i <= cnt ; i++ ) e[ i ].val -= mid;
	}
	return printf( "%.2lf\n", r ), 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值