bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)
菜菜推荐的“水题”虐了我一天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并且权值有负数的话使用填表法可能会导致从不合法状态转移。
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- using namespace std;
- const int maxn=,inf=1e9;
- struct poi{int too,pre;}e[maxn];
- int n,k,x,tot,cnt,mx;
- int dfn[maxn],nxt[maxn],last[maxn],s[maxn],p[maxn];
- double f[maxn][maxn],w[maxn];
- inline void read(int &k)
- {
- int f=;k=;char c=getchar();
- while(c<''||c>'')c=='-'&&(f=-),c=getchar();
- while(c<=''&&c>='')k=k*+c-'',c=getchar();
- k*=f;
- }
- void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}
- void dfs(int x)
- {
- dfn[x]=cnt++;
- for(int i=last[x];i;i=e[i].pre)dfs(e[i].too);
- nxt[dfn[x]]=cnt;
- }
- int main()
- {
- read(k);read(n);
- for(int i=;i<=n;i++)read(s[i]),read(p[i]),read(x),add(x,i),mx=max(mx,p[i]);
- dfs();
- double l=,r=1e4;
- while(r-l>1e-)
- {
- double mid=(l+r)/;
- for(int i=;i<=n;i++)w[dfn[i]]=1.0*p[i]-mid*s[i];
- for(int i=;i<=n+;i++)for(int j=;j<=k+;j++)f[i][j]=-inf;
- for(int i=;i<=n;i++)
- for(int j=;j<=min(i,k+);j++)
- {
- if(f[i][j]>f[nxt[i]][j])f[nxt[i]][j]=f[i][j];
- if(f[i][j]+w[i]>f[i+][j+])f[i+][j+]=f[i][j]+w[i];
- }
- if(f[n+][k+]>1e-)l=mid;else r=mid;
- }
- printf("%.3lf\n",l);
- }
第二种做法仅能在代价为选取点数的情况下使用,直接在树上做背包,但是在对于每一个子节点做完背包之后才把子节点的size加进父节点,这样的复杂度也是O(N^2)的。
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<cstdio>
- using namespace std;
- const int maxn=;
- double eps=1e-,inf=1e12;
- struct poi{int too,pre;}e[maxn];
- int n,k,x,tot,sum;
- int p[maxn],s[maxn],size[maxn],last[maxn];
- double f[maxn][maxn],w[maxn],g[maxn];
- void read(int &k)
- {
- int f=;k=;char c=getchar();
- while(c<''||c>'')c=='-'&&(f=-),c=getchar();
- while(c<=''&&c>='')k=k*+c-'',c=getchar();
- k*=f;
- }
- void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}
- void dfs(int x)
- {
- size[x]=;f[x][]=w[x];
- for(int i=last[x];i;i=e[i].pre)
- {
- dfs(e[i].too);
- for(int j=;j<=size[x]+size[e[i].too];j++)g[j]=f[x][j];
- for(int j=;j<=size[x];j++)
- for(int k=;k<=size[e[i].too];k++)
- g[j+k]=max(g[j+k],f[x][j]+f[e[i].too][k]);
- size[x]+=size[e[i].too];
- for(int j=;j<=size[x];j++)f[x][j]=g[j];
- }
- }
- int main()
- {
- read(k);read(n);
- for(int i=;i<=n;i++)read(s[i]),read(p[i]),read(x),add(x,i);
- double l=,r=1e4;
- while(r-l>eps)
- {
- double mid=(l+r)/;
- for(int i=;i<=n;i++)w[i]=1.0*p[i]-mid*s[i];
- for(int i=;i<=n;i++)for(int j=;j<=k+;j++)f[i][j]=-inf;
- dfs();if(f[][k+]>eps)l=mid;else r=mid;
- }
- printf("%.3lf\n",l);
- }
bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)的更多相关文章
- 【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp
题目描述 JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了 ...
- BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包)
BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包) 标签:题解 阅读体验 BZOJ题目链接 洛谷题目链接 具体实现 看到分数和最值,考虑分数规划 我们要求的是一个\(\dfrac{ ...
- [JSOI2016]最佳团体 DFS序/树形DP
题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...
- bzoj4753[JSOI2016]最佳团体
题意:01分数规划,但可选的数字之间存在森林形的依赖关系(可以认为0号点是个虚根,因为并不能选). 虽然有森林形的依赖关系,但还是可以套分数规划的思路,二分答案k,判断是否存在一个比值大于k的方案 即 ...
- Gym - 101002D:Programming Team (01分数规划+树上依赖背包)
题意:给定一棵大小为N的点权树(si,pi),现在让你选敲好K个点,需要满足如果如果u被选了,那么fa[u]一定被选,现在要求他们的平均值(pi之和/si之和)最大. 思路:均值最大,显然需要01分数 ...
- BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)
看到比值先二分答案.于是转化成一个非常裸的树形背包.直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对.这里使用一种更通用的dfs序优化树形背包写法.https://www.cnb ...
- BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划
BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划 Description JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人 ...
- BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划
BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划 又是一道卡精度卡得我头皮发麻的题-- 题面(--蜜汁改编版) YL大哥是24OI的大哥,有一天,他想要从\(N\)个候选人中选 ...
- 【BZOJ4753】最佳团体(分数规划,动态规划)
[BZOJ4753]最佳团体(分数规划,动态规划) 题面 BZOJ Description JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一 ...
随机推荐
- PHP:Iterator(迭代器)接口和生成器
迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...
- fastdfs+nginx+image_filter安装与生成缩略图
fastdfs简介 类似google FS的一个轻量级分布式文件系统,纯C实现,支持linux.FreeBSD等UNIX系统: 只能通过API访问,不支持POXIS: 文件不分块存储,上传的文件和OS ...
- EasyUI validatebox 自定义ajax验证用户名是否已存在
<td><input type="text" id="userName" name="userName" class=&q ...
- Tree - XGBoost with parameter description
In the previous post, we talk about a very popular Boosting algorithm - Gradient Boosting Decision T ...
- POWERDESIGNER生成的代码有引号
昨天在用powerdesigner画的一个导入ORACLE中.发现都带了双引号, 当时没在意,以为是分隔符.那想后要在ORACLE查询表是一定要输入双引号才能查询.. 后来才知道而这在oracle 中 ...
- [redis] linux下哨兵篇(3)
一.前言1.为何部署sentinel哨兵前文redis主从架构中,当主服务故障时,需要手动将从服务切换为主服务,sentinel服务就是将这个过程自动化.主要功能有:1)不时监控主从服务正常运行2)可 ...
- underscore.js源码解析(三)
最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...
- 王者荣耀交流协会final冲刺第五次scrum会议
成员王超,高远博,冉华,王磊,王玉玲,任思佳,袁玥全部到齐,王磊拍照. master:高远博 2.时间跨度 2017年12月5日 18:00 - 18:31,总计31分钟 3.地点 一食堂二楼沙发座椅 ...
- php addslashes和stripslashes函数
addslashes — 使用反斜线引用字符串 stripslashes — 反引用一个引用字符串 Example #1 一个 addslashes() 例子 <?php$str = &qu ...
- 给新建的kvm虚拟机创建网络接口
(一)首先必须创建网卡连接桥接口的启动脚本和停止脚本,其中脚本中的 $1:表示为虚拟机的网卡的右边接口,这两个脚本就是讲虚拟机的网卡的右边接口接在网桥上,实现桥接模型 # 1:/etc/qem ...