水个博客玩。
$01$分数规划。
题目要求$frac{F - sum_{i = 1}^{n}C_i}{T_i}$最大,设$frac{F - sum_{i}C_i}{T_i} geq e$,移项一下可以得到$F - sum_{i }(e * T_i + C_i) geq 0$。
那么在外层二分一个$e$,然后把所有边的权值设成$e * T_i + C_i$做最小生成树,假设这样子生成树的权值为$res$,如果$F - res > 0$ 那么说明答案还可以更大,否则更小。
时间复杂度$O(mlogmlogn(MaxInt))$。
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; typedef double db; const int N = 405; const int M = 10005; const db eps = 1e-6; const db inf = 1e10; int n, m, ufs[N]; ll cur; struct Pathway { int u, v; ll c, t; db val; friend bool operator < (const Pathway &x, const Pathway &y) { return x.val < y.val; } } pat[M]; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } int find(int x) { return x == ufs[x] ? x : ufs[x] = find(ufs[x]); } inline bool chk(db mid) { for(int i = 1; i <= m; i++) pat[i].val = mid * pat[i].t + 1.0 * pat[i].c; sort(pat + 1, pat + 1 + m); for(int i = 1; i <= n; i++) ufs[i] = i; int cnt = 0; db res = 0; for(int i = 1; i <= m; i++) { int u = find(pat[i].u), v = find(pat[i].v); if(u == v) continue; ufs[u] = v; ++cnt; res += pat[i].val; if(cnt >= n - 1) break; } return (1.0 * cur - res) > 0; } int main() { read(n), read(m), read(cur); for(int i = 1; i <= m; i++) read(pat[i].u), read(pat[i].v), read(pat[i].c), read(pat[i].t); db ln = 0.0, rn = inf, mid, res = 0.0; for(; ln + eps <= rn; ) { mid = (ln + rn) * 0.5; if(chk(mid)) ln = mid, res = mid; else rn = mid; } printf("%.4f ", res); return 0; }