【题目链接】
【思路要点】
- 分数规划,然后树上背包判断是否可行。
- 时间复杂度\(O(N^2LogW)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3005; const double eps = 1e-5; const double INF = 1e99; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m; vector <int> a[MAXN]; double val[MAXN], dp[MAXN][MAXN]; int cost[MAXN], power[MAXN]; int size[MAXN], father[MAXN]; void merge(double *from, int totf, double *to, int &tott) { for (int i = min(tott + totf, m); i >= 1; i--) for (int j = max(1, i - totf); j <= tott && j <= i; j++) chkmax(to[i], to[j] + from[i - j]); tott = min(tott + totf, m); } void work(int pos) { size[pos] = 1; dp[pos][1] = val[pos]; for (unsigned i = 0; i < a[pos].size(); i++) { work(a[pos][i]); merge(dp[a[pos][i]], size[a[pos][i]], dp[pos], size[pos]); } } int main() { read(m), read(n); m++; double l = 0, r = 0; for (int i = 1; i <= n; i++) { read(cost[i]), read(power[i]), read(father[i]); a[father[i]].push_back(i); chkmax(r, 1.0 * power[i] / cost[i]); } while (l + eps < r) { double mid = (l + r) / 2; for (int i = 0; i <= n; i++) for (int j = 1; j <= m; j++) dp[i][j] = -INF; for (int i = 1; i <= n; i++) val[i] = power[i] - mid * cost[i]; work(0); if (dp[0][m] >= 0) l = mid; else r = mid; } printf("%.3lf\n", (l + r) / 2); return 0; }