码迷,mamicode.com
首页 > Web开发 > 详细

「JSOI2016」最佳团体

时间:2020-02-14 14:30:28      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:dfs   main   ace   can   简单   const   for   check   bool   

01分数规划

显然可以二分最大比值x,来验证是否可行

记当前比值为x,总战斗值为P与总招募费用为S

则 P - x*S >= 0

设 wi = pi - x*si

即 w1 + w2 + ... + wk >= 0

就转化为选k个节点,它们的w值非负,树上简单地dp一下就可求得

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2505;
 5 
 6 double l, r = 1e4, mid, f[N][N], w[N], ans, eps = 1e-5;
 7 int siz[N], fa[N], p[N], s[N];
 8 int n, m, first[N], cnt;
 9 struct Edge {
10     int to, next;
11 } e[N];
12 
13 void dfs(int u) {
14     siz[u] = 1;
15     f[u][1] = w[u];
16     for (int i = first[u]; i != -1; i = e[i].next) {
17         int v = e[i].to;
18         dfs(v);
19         siz[u] += siz[v];
20         for (int j = min(siz[u], m); j >= 2; j--)
21             for (int k = 1; k <= min(j - 1, siz[v]); k++) f[u][j] = max(f[u][j], f[v][k] + f[u][j - k]);
22     }
23 }
24 
25 bool check(double x) {
26     memset(f, -0x3f, sizeof(f));
27     for (int i = 0; i <= n; i++) f[i][0] = 0;
28     for (int i = 1; i <= n; i++) w[i] = (double)p[i] - s[i] * x;
29     dfs(0);
30     return f[0][m] >= 0;
31 }
32 
33 void add(int u, int v) {
34     e[cnt].to = v;
35     e[cnt].next = first[u];
36     first[u] = cnt++;
37 }
38 
39 int main() {
40     memset(first, -1, sizeof(first));
41     cin >> m >> n;
42     m++;
43     for (int i = 1; i <= n; i++) {
44         scanf("%d%d%d", &s[i], &p[i], &fa[i]);
45         add(fa[i], i);
46     }
47     while (r - l > eps) {
48         mid = (r + l) / 2;
49         dfs(0);
50         if (check(mid))
51             l = mid + eps, ans = mid;
52         else
53             r = mid - eps;
54     }
55     printf("%.3f\n", ans);
56 }

 

「JSOI2016」最佳团体

标签:dfs   main   ace   can   简单   const   for   check   bool   

原文地址:https://www.cnblogs.com/ympc2005/p/12307225.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!