传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1486
二分不说了,关键是判负圈,我们令每个点都有一个dist,只有让它更小时才能继续走,这样如果走到了之前的节点,就一定有负圈了,注意一定要每个点都去试一试。。。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define INF 1e10 #define eps 1e-10 const int maxn = 3010, maxm = 10010; int fir[maxn], edge[maxm], next[maxm]; double v[maxm], d[maxn], w[maxm]; bool vis[maxn]; int n, m, cnt; void addedge(int a, int b, double c) { edge[cnt] = b; next[cnt] = fir[a]; fir[a] = cnt; w[cnt ++] = c; return; } bool dfs(int x) { vis[x] = true; for(int i = fir[x]; ~i ; i = next[i]) { int p = edge[i]; if(d[p] > d[x] + v[i]) { if(!vis[p]) { d[p] = d[x] + v[i]; if(dfs(p)) return true; } else return true; } } vis[x] = false; return false; } bool solve(double x) { for(int i = 0; i < cnt; i ++) v[i] = w[i] - x; memset(vis, false, sizeof(vis)); memset(d, 0, sizeof(d)); for(int i = 1; i <= n; i ++) { if(dfs(i)) return true; } return false; } int main() { memset(fir, -1, sizeof(fir)); scanf("%d%d", &n, &m); int u, v; double a, l = INF, r = -INF; for(int i = 1; i <= m; i ++) { scanf("%d%d%lf", &u, &v, &a); addedge(u, v, a); l = min(l, a), r = max(r, a); } while(r - l > eps) { double mid = (l + r) / 2.0; if(solve(mid)) r = mid; else l = mid; } printf("%.8lf\n", l); return 0; }