[树形dp][二分] Jzoj P4512 最佳团队

Description

 

Input

Output

 

Sample Input

1 2
1000 1 0
1 1000 1

Sample Output

0.001
 

Data Constraint

 

题解

  • 题目大意:在一棵树上,找到一棵树使他们费用和比贡献和的比值最小
  • 比值最小,也差不多是最大值最小的意思,那么就可以考虑二分一个值,然后就是常规操作dp判断
  • 根据题目来看很显然就是一个树上背包
  • 设f[i][j]为以i为根的树里选择j个点的(贡献和-费用和*二分比值)
  • 显然如果最后dp完后,f[0][k+1]>0的话,就是成立的
  • 考虑转移,那么就可以枚举两个值,一个是当前子树选点的个数,一个是当前点的儿子的子树选点的个数,转移方程显然

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #define N 2510
 4 #define eps 1e-5
 5 using namespace std;
 6 struct edge { int to,from; }e[N];
 7 int k,n,bz[N],p[N],s[N],ans,t;
 8 double f[N][N],l,r,mid;
 9 char ch;
10 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
11 void dp(int x,int y)
12 {
13     bz[x]=1;
14     if (y==0) return;
15     for (int i=head[x];i;i=e[i].from)
16     {
17         dp(e[i].to,y-1),bz[x]+=bz[e[i].to];
18         for (int j=min(y,bz[x]);j;j--)
19                 for (int k=min(j,bz[e[i].to]);k;k--)
20                     f[x][j]=max(f[x][j],f[e[i].to][k]+f[x][j-k]);
21     }
22     for (int i=min(y,bz[x]);i;i--) f[x][i]=f[x][i-1]+p[x]-s[x]*mid;
23 }
24 int main()
25 {
26     scanf("%d%d",&k,&n);
27     for (int i=1,x;i<=n;i++) scanf("%d%d%d",&s[i],&p[i],&x),insert(x,i);
28     l=0,r=3;
29     while (r-l<eps)
30     {
31         mid=l+r>>1;
32         memset(f,127,sizeof(f));
33         for (int i=0;i<=n;i++) f[i][0]=0;
34         dp(0,k+1);
35         if (f[0][k+1]) l=mid+eps; else r=mid-eps;
36     }
37     printf("%.3lf",l+r>>1);
38 }

 

posted @ 2019-01-18 16:07  BEYang_Z  阅读(206)  评论(0编辑  收藏  举报