BZOJ1486: [HNOI2009]最小圈

1486: [HNOI2009]最小圈

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 2728 Solved: 1315
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

4 5

1 2 5

2 3 5

3 1 5

2 4 3

4 1 3

Sample Output

3.66666667

HINT

Source

题解

\(0/1\)分数规划裸题
学了一发\(dfsspfa\)判负环
依据是任何一个负环都可以从一个点开始走,总是走最短路减小且最短路为负的点到终点
\(d\)全部负为\(0\),就可以保证走的每一步都是负的。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a < b ? a : b;}
inline int abs(int x){return x < 0 ? -x : x;}
inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}

inline void read(int &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9') c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 3000 + 10;
const int MAXM = 10000 + 10;
const double eps = 0.000000001;
struct Edge
{
	int u,v,nxt;
	double w;
	Edge(int _u, int _v, double _w, int _nxt){u = _u, v = _v, w = _w, nxt = _nxt;}
	Edge(){}
}edge[MAXM << 1];
int head[MAXN], cnt, vis[MAXN], n, m, sum, flag;
double d[MAXN];
inline void insert(int a, int b, double c)
{
	edge[++ cnt] = Edge(a, b, c, head[a]), head[a] = cnt;
}
void dfs(int x)
{
	if(flag) return;
	vis[x] = 1;
	for(int pos = head[x];pos;pos = edge[pos].nxt)
	{
		int v = edge[pos].v;
		if(d[v] > d[x] + edge[pos].w)
		{
			if(vis[v])
			{
				flag = 1;
				break;
			}
			d[v] = d[x] + edge[pos].w;
			dfs(v);
		}
	}
	vis[x] = 0;
}
int main()
{
	read(n), read(m);
	for(int i = 1;i <= m;++ i)
	{
		int tmp1, tmp2;double tmp3;
		read(tmp1), read(tmp2), scanf("%lf", &tmp3);
		insert(tmp1, tmp2, tmp3);
		sum += abs(tmp3);
	}
	double l = -sum, r = sum, mid, ans;
	while(r - l >= eps)
	{
		mid = (l + r) / 2;flag = 0;
		for(int i = 1;i <= cnt;++ i) edge[i].w -= mid;
		for(int i = 1;i <= n;++ i)
		{
			memset(d, 0, sizeof(d));
			dfs(i);
			if(flag) break;
		}
		if(flag) r = mid;
		else l = mid, ans = mid;
		for(int i = 1;i <= cnt;++ i) edge[i].w += mid;
	}
	printf("%.8lf", ans);
    return 0;
}
posted @ 2018-03-11 17:25  嘒彼小星  阅读(191)  评论(0编辑  收藏  举报