菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~

  显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解。

  第一次接触树形依赖背包,所以之前写的十几发WA和TLE都是错误写法,我还是naive啊T T

  树形依赖背包的普遍做法是按dfs序DP,设f[i][j]为dfs序为i的点,已经选了j个点的最大价值,nxt[i]为i的下一个子树的dfs序则有:

  f[nxt[i]][j]=f[i][j]

  f[i+1][j+1]=f[i][j]+w[i]

  注意树形依赖背包最好使用刷表法,因为如果要求代价必须为k并且权值有负数的话使用填表法可能会导致从不合法状态转移。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<cstdio>
  5. #include<cmath>
  6. #include<algorithm>
  7. using namespace std;
  8. const int maxn=,inf=1e9;
  9. struct poi{int too,pre;}e[maxn];
  10. int n,k,x,tot,cnt,mx;
  11. int dfn[maxn],nxt[maxn],last[maxn],s[maxn],p[maxn];
  12. double f[maxn][maxn],w[maxn];
  13. inline void read(int &k)
  14. {
  15. int f=;k=;char c=getchar();
  16. while(c<''||c>'')c=='-'&&(f=-),c=getchar();
  17. while(c<=''&&c>='')k=k*+c-'',c=getchar();
  18. k*=f;
  19. }
  20. void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}
  21. void dfs(int x)
  22. {
  23. dfn[x]=cnt++;
  24. for(int i=last[x];i;i=e[i].pre)dfs(e[i].too);
  25. nxt[dfn[x]]=cnt;
  26. }
  27. int main()
  28. {
  29. read(k);read(n);
  30. for(int i=;i<=n;i++)read(s[i]),read(p[i]),read(x),add(x,i),mx=max(mx,p[i]);
  31. dfs();
  32. double l=,r=1e4;
  33. while(r-l>1e-)
  34. {
  35. double mid=(l+r)/;
  36. for(int i=;i<=n;i++)w[dfn[i]]=1.0*p[i]-mid*s[i];
  37. for(int i=;i<=n+;i++)for(int j=;j<=k+;j++)f[i][j]=-inf;
  38. for(int i=;i<=n;i++)
  39. for(int j=;j<=min(i,k+);j++)
  40. {
  41. if(f[i][j]>f[nxt[i]][j])f[nxt[i]][j]=f[i][j];
  42. if(f[i][j]+w[i]>f[i+][j+])f[i+][j+]=f[i][j]+w[i];
  43. }
  44. if(f[n+][k+]>1e-)l=mid;else r=mid;
  45. }
  46. printf("%.3lf\n",l);
  47. }

  第二种做法仅能在代价为选取点数的情况下使用,直接在树上做背包,但是在对于每一个子节点做完背包之后才把子节点的size加进父节点,这样的复杂度也是O(N^2)的。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<cstdio>
  5. using namespace std;
  6. const int maxn=;
  7. double eps=1e-,inf=1e12;
  8. struct poi{int too,pre;}e[maxn];
  9. int n,k,x,tot,sum;
  10. int p[maxn],s[maxn],size[maxn],last[maxn];
  11. double f[maxn][maxn],w[maxn],g[maxn];
  12. void read(int &k)
  13. {
  14. int f=;k=;char c=getchar();
  15. while(c<''||c>'')c=='-'&&(f=-),c=getchar();
  16. while(c<=''&&c>='')k=k*+c-'',c=getchar();
  17. k*=f;
  18. }
  19. void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}
  20. void dfs(int x)
  21. {
  22. size[x]=;f[x][]=w[x];
  23. for(int i=last[x];i;i=e[i].pre)
  24. {
  25. dfs(e[i].too);
  26. for(int j=;j<=size[x]+size[e[i].too];j++)g[j]=f[x][j];
  27. for(int j=;j<=size[x];j++)
  28. for(int k=;k<=size[e[i].too];k++)
  29. g[j+k]=max(g[j+k],f[x][j]+f[e[i].too][k]);
  30. size[x]+=size[e[i].too];
  31. for(int j=;j<=size[x];j++)f[x][j]=g[j];
  32. }
  33. }
  34. int main()
  35. {
  36. read(k);read(n);
  37. for(int i=;i<=n;i++)read(s[i]),read(p[i]),read(x),add(x,i);
  38. double l=,r=1e4;
  39. while(r-l>eps)
  40. {
  41. double mid=(l+r)/;
  42. for(int i=;i<=n;i++)w[i]=1.0*p[i]-mid*s[i];
  43. for(int i=;i<=n;i++)for(int j=;j<=k+;j++)f[i][j]=-inf;
  44. dfs();if(f[][k+]>eps)l=mid;else r=mid;
  45. }
  46. printf("%.3lf\n",l);
  47. }

bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)的更多相关文章

  1. 【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp

    题目描述 JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了 ...

  2. BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包)

    BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包) 标签:题解 阅读体验 BZOJ题目链接 洛谷题目链接 具体实现 看到分数和最值,考虑分数规划 我们要求的是一个\(\dfrac{ ...

  3. [JSOI2016]最佳团体 DFS序/树形DP

    题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...

  4. bzoj4753[JSOI2016]最佳团体

    题意:01分数规划,但可选的数字之间存在森林形的依赖关系(可以认为0号点是个虚根,因为并不能选). 虽然有森林形的依赖关系,但还是可以套分数规划的思路,二分答案k,判断是否存在一个比值大于k的方案 即 ...

  5. Gym - 101002D:Programming Team (01分数规划+树上依赖背包)

    题意:给定一棵大小为N的点权树(si,pi),现在让你选敲好K个点,需要满足如果如果u被选了,那么fa[u]一定被选,现在要求他们的平均值(pi之和/si之和)最大. 思路:均值最大,显然需要01分数 ...

  6. BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)

    看到比值先二分答案.于是转化成一个非常裸的树形背包.直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对.这里使用一种更通用的dfs序优化树形背包写法.https://www.cnb ...

  7. BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划

    BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划 Description JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人 ...

  8. BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划

    BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划 又是一道卡精度卡得我头皮发麻的题-- 题面(--蜜汁改编版) YL大哥是24OI的大哥,有一天,他想要从\(N\)个候选人中选 ...

  9. 【BZOJ4753】最佳团体(分数规划,动态规划)

    [BZOJ4753]最佳团体(分数规划,动态规划) 题面 BZOJ Description JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一 ...

随机推荐

  1. PHP:Iterator(迭代器)接口和生成器

    迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...

  2. fastdfs+nginx+image_filter安装与生成缩略图

    fastdfs简介 类似google FS的一个轻量级分布式文件系统,纯C实现,支持linux.FreeBSD等UNIX系统: 只能通过API访问,不支持POXIS: 文件不分块存储,上传的文件和OS ...

  3. EasyUI validatebox 自定义ajax验证用户名是否已存在

    <td><input type="text" id="userName" name="userName" class=&q ...

  4. Tree - XGBoost with parameter description

    In the previous post, we talk about a very popular Boosting algorithm - Gradient Boosting Decision T ...

  5. POWERDESIGNER生成的代码有引号

    昨天在用powerdesigner画的一个导入ORACLE中.发现都带了双引号, 当时没在意,以为是分隔符.那想后要在ORACLE查询表是一定要输入双引号才能查询.. 后来才知道而这在oracle 中 ...

  6. [redis] linux下哨兵篇(3)

    一.前言1.为何部署sentinel哨兵前文redis主从架构中,当主服务故障时,需要手动将从服务切换为主服务,sentinel服务就是将这个过程自动化.主要功能有:1)不时监控主从服务正常运行2)可 ...

  7. underscore.js源码解析(三)

    最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...

  8. 王者荣耀交流协会final冲刺第五次scrum会议

    成员王超,高远博,冉华,王磊,王玉玲,任思佳,袁玥全部到齐,王磊拍照. master:高远博 2.时间跨度 2017年12月5日 18:00 - 18:31,总计31分钟 3.地点 一食堂二楼沙发座椅 ...

  9. php addslashes和stripslashes函数

    addslashes — 使用反斜线引用字符串 stripslashes — 反引用一个引用字符串   Example #1 一个 addslashes() 例子 <?php$str = &qu ...

  10. 给新建的kvm虚拟机创建网络接口

    (一)首先必须创建网卡连接桥接口的启动脚本和停止脚本,其中脚本中的 $1:表示为虚拟机的网卡的右边接口,这两个脚本就是讲虚拟机的网卡的右边接口接在网桥上,实现桥接模型     # 1:/etc/qem ...