传送门: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;
}