1. 程式人生 > >Luogu 4951 [USACO 2001 OPEN]地震

Luogu 4951 [USACO 2001 OPEN]地震

水個部落格玩。

$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:

#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\n", res); return 0; }
View Code