01分数规划复习。
这东西有一个名字叫做最优比率环。
首先这个答案具有单调性,我们考虑如何检验。
设$frac{sum_{i = 1}^{n}F_i}{sum_{i = 1}^{n}T_i} = e$,我们需要检验的就是$sum_{i = 1}^{n}(F_i - mid * T_i) geq 0$是否存在。
感觉这玩意不好算,再变形一下:$sum_{i = 1}^{n}(e * T_i - F_i) < 0$,就变成一个负环的检验了。
$F_i$应当可以任取一条有向边的入点和出点。
注意二分时的边界问题。
时间复杂度$O(logn (spfa???))$。
Code:
#include <cstdio> #include <cstring> using namespace std; typedef long double db; const int N = 1005; const int M = 5005; const db inf = 1e10; const db eps = 1e-6; int n, m, tot = 0, head[N]; db dis[N], a[N]; bool vis[N], ex; struct Edge { int to, nxt; db val; } e[M]; inline void add(int from, int to, db val) { e[++tot].to = to; e[tot].val = val; e[tot].nxt = head[from]; head[from] = tot; } template <typename T> inline void chkMax(T &x, T y) { if(y > x) x = y; } template <typename T> inline void chkMin(T &x, T y) { if(y < x) x = y; } void dfs(int x, db mid) { if(ex) return; vis[x] = 1; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(dis[y] > dis[x] + mid * e[i].val - a[y]) { dis[y] = dis[x] + mid * e[i].val - a[y]; if(vis[y]) { ex = 1; return; } dfs(y, mid); } } vis[x] = 0; } inline bool chk(db mid) { for(int i = 1; i <= n; i++) { dis[i] = 0.0; vis[i] = 0; } ex = 0; for(int i = 1; i <= n; i++) { dfs(i, mid); if(ex) break; } return ex; } int main() { scanf("%d%d", &n, &m); db ln = 0.0, rn = 0.0, mid, res; for(int i = 1; i <= n; i++) scanf("%Lf", &a[i]); for(int i = 1; i <= m; i++) { int x, y; db v; scanf("%d%d%Lf", &x, &y, &v); add(x, y, v); rn += v; } for(; ln + eps <= rn; ) { mid = (ln + rn) * 0.5; if(chk(mid)) ln = mid, res = mid; else rn = mid; } printf("%.2Lf ", res); return 0; }