分数规划
题目大意:有一棵
最大。你需要保证对于你选择的一个树上结点,它的父亲一定被选中。求出这个最大的比值。
如果每个点都只有一个价值(设为
定义
如果 合并方式得当 ,则可以在
但是,我们是让一个分式的值最大化,然而这个分式的分母又不确定,怎么办呢?
首先我们明确一个性质:设最后最大化的答案为
那么,我们就可以用二分的思想解决这个问题。每次选择一个
这就是分数规划的基本思想。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // luogu-judger-enable-o2 #include <algorithm> #include <cstdio> #include <cstring> using namespace std; const int maxn = 2510; int k, n, rr, cur, h[maxn], nxt[maxn * 2], p[maxn * 2], siz[maxn]; double s[maxn], pp[maxn], l, r, mid, v[maxn], f[maxn][maxn]; void add_edge(int x, int y) { cur++; nxt[cur] = h[x]; h[x] = cur; p[cur] = y; } void dfs(int x, int fa) { siz[x] = 1; f[x][0] = 0; f[x][1] = v[x]; for (int i = h[x]; i != -1; i = nxt[i]) if (p[i] != fa) { dfs(p[i], x); for (int j = siz[x]; j >= 1; j--) for (int k = 0; k <= siz[p[i]]; k++) f[x][j + k] = max(f[x][j + k], f[x][j] + f[p[i]][k]); siz[x] += siz[p[i]]; } } int main() { memset(h, -1, sizeof h); scanf("%d%d", &k, &n); for (int i = 1; i <= n; i++) scanf("%lf%lf%d", s + i, pp + i, &rr), add_edge(rr, i), add_edge(i, rr); r = 10000.0; while (r - l > 1e-4) { mid = (l + r) * 0.5; for (int i = 1; i <= n; i++) v[i] = pp[i] - mid * s[i]; for (int i = 0; i < maxn; i++) for (int j = 0; j < maxn; j++) f[i][j] = -2e9; dfs(0, -1); if (f[0][k + 1] > 0) l = mid; else r = mid; } printf("%.3lf\n", l); return 0; } |
习题¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用