[BZOJ1486][HNOI2009]最小圈

[BZOJ1486][HNOI2009]最小圈

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

输出示例

3.66666667

数据规模及约定

见“试题描述

题解

分数规划,二分答案 x 后每条边的边权减去 x,若有负环则表明答案小于等于 x。

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

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define maxn 3010
#define maxm 10010
#define LL long long

int n, m, head[maxn], nxt[maxm], to[maxm];
LL dist[maxm], eval[maxm];

void AddEdge(int a, int b, LL c) {
	to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
	return ;
}

LL d[maxn];
bool vis[maxn];
bool spfa(int u) {
	vis[u] = 1;
	for(int e = head[u]; e; e = nxt[e]) if(d[to[e]] >= d[u] + eval[e]) {
		if(vis[to[e]]) return 1;
		d[to[e]] = d[u] + eval[e];
		if(spfa(to[e])) return 1;
	}
	vis[u] = 0;
	return 0;
}
bool has_ncyc() {
	memset(vis, 0, sizeof(vis));
	memset(d, 0, sizeof(d));
	for(int i = 1; i <= n; i++)
		if(spfa(i)) return 1;
	return 0;
}

int main() {
	LL l = 0, r = 0;
	
	n = read(); int M = read();
	for(int i = 1; i <= M; i++) {
		int a = read(), b = read(); LL c = (LL)read() * 2000000000ll;
		AddEdge(a, b, c); r += c;
	}
	
	l = -r;
	while(l < r) {
		LL mid = l + r >> 1;
		for(int i = 1; i <= m; i++) eval[i] = dist[i] - mid;
		if(has_ncyc()) r = mid; else l = mid + 1;
	}
	
	printf("%.8lf\n", (double)l / 2e9);
	
	return 0;
}

 

posted @ 2017-05-18 09:04  xjr01  阅读(230)  评论(0编辑  收藏  举报