BZOJ4753: [Jsoi2016]最佳团体

$n \leq 2500$个人选$m \leq n$个,每人有花费有收益,还有依赖人,选他前必须选依赖人。问最大的收益花费比。

01分数规划。$\sum p_i-ts_i \leq 0$,这式子成立时要把$t$调小,不成立时要把$t$调大,我们希望$t$大,就尽可能让他不成立,所以就尽可能让左边大。

然后就是树形依赖背包。$f(i,j)$--dfs序上$i$处往后选$j$个的最大值,$f(i,j)=max(f(i+1,j-1)+val_i,f(k,j))$,其中$k$是$i$子树的最后一个节点的下一位。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 //#include<math.h>
 5 //#include<queue>
 6 //#include<vector>
 7 #include<algorithm>
 8 //#include<iostream>
 9 //#include<assert.h>
10 using namespace std;
11 
12 int n,m;
13 #define maxn 2511
14 double f[maxn][maxn],val[maxn];
15 int p[maxn],s[maxn];
16 
17 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2;
18 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
19 int id[maxn],rr[maxn],len=0;
20 void predfs(int x,int fa)
21 {
22     id[++len]=x;
23     for (int i=first[x];i;i=edge[i].next)
24     {
25         Edge &e=edge[i]; if (e.to==fa) continue;
26         predfs(e.to,x);
27     }
28     rr[x]=len;
29 }
30 
31 bool check(double x)
32 {
33     for (int i=1;i<=n;i++) val[i]=p[i]-x*s[i];
34     f[len][0]=0; f[len][1]=val[id[len]]; for (int i=2;i<=n+1;i++) f[len][i]=-1e18;
35     for (int i=len-1;i>1;i--)
36     {
37         f[i][0]=0;
38         for (int j=1;j<=len;j++)
39         {
40             f[i][j]=f[i+1][j-1]+val[id[i]];
41             if (rr[id[i]]<len) f[i][j]=max(f[i][j],f[rr[id[i]]+1][j]);
42         }
43     }
44     return f[2][m]<=0;
45 }
46 
47 int main()
48 {
49     scanf("%d%d",&m,&n);
50     for (int i=1,x;i<=n;i++) scanf("%d%d%d",&s[i],&p[i],&x),in(x,i);
51     predfs(0,-1);
52     
53     double L=0,R=1e4+3;
54     while (R-L>1e-4)
55     {
56         double mid=(L+R)/2;
57         if (check(mid)) R=mid; else L=mid;
58     }
59     printf("%.3lf\n",L);
60     return 0;
61 }
View Code

 

posted @ 2018-04-12 12:58  Blue233333  阅读(173)  评论(0编辑  收藏  举报