zoukankan      html  css  js  c++  java
  • [JSOI 2016] 最佳团体(树形背包+01分数规划)

    4753: [Jsoi2016]最佳团体

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 2003  Solved: 790
    [Submit][Status][Discuss]

    Description

    JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号。方便起见,JYY的编号是0号。每个候选人都由一位
    编号比他小的候选人Ri推荐。如果Ri=0则说明这个候选人是JYY自己看上的。为了保证团队的和谐,JYY需要保证,
    如果招募了候选人i,那么候选人Ri"也一定需要在团队中。当然了,JYY自己总是在团队里的。每一个候选人都有
    一个战斗值Pi",也有一个招募费用Si"。JYY希望招募K个候选人(JYY自己不算),组成一个性价比最高的团队。
    也就是,这K个被JYY选择的候选人的总战斗值与总招募总费用的比值最大。
     

    Input

    输入一行包含两个正整数K和N。
    接下来N行,其中第i行包含3个整数Si,Pi,Ri表示候选人i的招募费用,战斗值和推荐人编号。
    对于100%的数据满足1≤K≤N≤2500,0<"Si,Pi"≤10^4,0≤Ri<i
     
     

    Output

    输出一行一个实数,表示最佳比值。答案保留三位小数。
     

    Sample Input

    1 2
    1000 1 0
    1 1000 1

    Sample Output

    0.001
    题解:
    一开始看到这题觉得是道水题,就和树上染色那道题一样,是个经典的$O(n^2)$的树上背包但是这道题不同的是转移有两个要素,并且这两个要素是作比的关系而不是简单的相加,一开始想两个分别转移,但是这两个东西他是同选取的,无法用正常方法维护,然后想了很长时间怎么进行转移,发现很不好转移,一点开标签发现需要一个新芝士点:01分数规划,然而自己不会啊qwq,上网学了一下,看了一下觉得也不是很难,大概介绍一下叭。
    01分数规划:

    01分数规划,简单的来说,就是有一些二元组$(s_i,p_i)$,从中选取一些二元组,使得$Sigma{s_i}/Sigma{p_i}$最大(最小)。

    这种题一类通用的解法就是,我们假设$x= Sigma{s_i}/Sigma{p_i}$的最大(小)值,那么就有$x*Sigma{p_i}=Sigma{s_i}$,即$Sigma{s_i}-x*Sigma{p_i}=0$。也就是说,当某一个值x满足上述式子的时候,它就是要求的值。我们可以想到枚举……不过再想想,这个可以二分答案。

    所以我们直接二分答案,当上述式子>0,说明答案小了,<0则说明答案大了,这样计算即可。


    好了,前置芝士解决了,那实际上这题就是道01分数规划和$O(n^2)$树形背包的裸题了,还有要注意的就是初始化问题,尤其注意的是每次二分答案都要再给dp数组附上初值,其实每次check的就是dp数组,即dp数组的值就是x。最后要注意的一点是因为他题目中说自己必须选,并且不计入总人数,所以要k++。

    总时间复杂度$O(n^2logn)$,稍卡常,luogu上要开O2。

    完结撒花。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<vector>
     7 #include<queue>
     8 #include<cstdlib>
     9 using namespace std;
    10 const int N=2505;
    11 const double eps=1e-5;
    12 int first[N],nex[N<<1],to[N<<1],tot;
    13 int vis[N],size[N];
    14 int n,k;
    15 int att[N],co[N],ri[N];
    16 double TerStegen[N];
    17 double f[N][N];
    18 void add(int a,int b){ to[++tot]=b,nex[tot]=first[a],first[a]=tot;}
    19 void dfs(int x){
    20     vis[x]=1;size[x]=1;
    21     f[x][1]=TerStegen[x];//
    22     for(int i=first[x];i;i=nex[i]){
    23         int y=to[i];
    24         //if(vis[y]) continue;//danxiangbian
    25         dfs(y);
    26         for(int j=min(size[x],k);j>=1;j--) for(int l=min(size[y],k);l>=1;l--) f[x][l+j]=max(f[x][l+j],f[y][l]+f[x][j]);//dayudengyu1?
    27         size[x]+=size[y];
    28     }
    29 }
    30 int check(double mid){
    31     int ju;
    32     for(int i=0;i<=2501;i++) for(int j=0;j<=2501;j++) f[i][j]=-88484848;
    33     //memset(f,0xcf,sizeof(f));
    34     for(int i=0;i<=n;i++) f[i][0]=0.0;
    35     for(int i=0;i<=n;i++) TerStegen[i]=1.0*att[i]-1.0*mid*1.0*co[i];
    36     dfs(0);
    37     //cout<<f[0][k]<<endl;
    38     if(f[0][k]>=0) ju=1;
    39     else ju=0;
    40     return ju;
    41 }
    42 int main(){
    43     scanf("%d%d",&k,&n);
    44     k++;//duliu
    45     for(int i=1;i<=n;++i){
    46         scanf("%d%d%d",&co[i],&att[i],&ri[i]);
    47         add(ri[i],i);
    48     }
    49     double l=0.0,r=2e7*1.0;
    50     double ans;
    51     while(l+eps<r){
    52         double mid=(l+r)/2;
    53         //cout<<mid<<" "<<l<<" "<<r<<endl; 
    54         if(check(mid)) l=mid;
    55         else r=mid;
    56     }
    57     printf("%.3lf",(l+r)/2);
    58 }
    View Code
  • 相关阅读:
    java map遍历并删除特定值
    控制反转,依赖注入
    【转】Spring MVC 标签总结
    Spring test
    oracle数据库的冷备份
    ORACLE的数据库知识(摘抄自其他博客园文章)
    禅道工具的下载和使用(原地址:https://www.cnblogs.com/ydnice/p/5800256.html)
    mysql数据库的锁表与解决办法(原博客url:http://www.cnblogs.com/wanghuaijun/p/5949934.html)
    把.exe的格式的运行程序加到电脑本地服务的办法(本文来源于百度)
    Struts2的学习自我总结
  • 原文地址:https://www.cnblogs.com/leom10/p/11440330.html
Copyright © 2011-2022 走看看