【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp
题目描述
输入
输出
样例输入
1 2
1000 1 0
1 1000 1
样例输出
0.001
题解
分数规划+树形背包dp
二分答案mid,题目便转化为求是否存在满足题目条件的集合V,使得$\frac{\sum\limits_{i\in V}p_i}{\sum\limits_{i\in V}s_i}\ge mid$,即$\sum\limits_{i\in V}(s_i-mid·p_i)\ge 0$。
这就转化为了一个树形dp问题。
令a[i]=s[i]-mid*p[i],表示i的性价比。设f[i][j]表示从子树i中选出j个且选i,可以获得的最大性价比之和,显然f[i][1]=a[i]。
那么对于每个i的子节点son,相当于有体积为1~si[son]共si[son]个物品放入背包内,每个物品可以放或不放。这相当于01背包问题。
但是这样dp的时间复杂度好像是$O(n^3)$的。
事实上,这里面的有效状态是很少的,如果只枚举有效状态,dp的时间复杂度将到达可以接受的$O(n^2)$。
具体粗略证明:
更新一棵子树的时间复杂度=更新该节点的子节点的时间复杂度+计算该节点的时间复杂度。
计算该节点的复杂度,如果采用最优策略,使用严格的有效区间范围来进行dp,时间复杂度应该为
$O(\sum\limits_{i=1}^m(1+\sum\limits_{j=1}^{i-1}si_j)·si_i)=O(\sum\limits_{i=1}^m\sum\limits_{j=1}^{i-1}si_j·si_i+\sum\limits_{i=1}^msi_i)=O((\sum\limits_{i=1}^msi_i)^2-\sum\limits_{i=1}^msi_i^2+\sum\limits_{i=1}^msi_i)=O(si_x^2-\sum\limits_{i=1}^msi_i^2+si_x)$,
其中$si_i(i\in[1,m])$表示x的第i个儿子节点的子树大小(总共有m个儿子节点),$si_x$表示x的子树大小。
而叶子节点的时间复杂度是$O(1)$的,进而我们可以使用累加法计算出总体dp的时间复杂度为$O(si_{root}^2+\sum\limits_{i=1}^nsi_i^2)=O(n^2)$。
因此总的时间复杂度是$O(n^2\log m)$。
为了避免精度误差带来的答案错误,建议固定二分c次,c值视情况而定,本题中取30可过。
另外由于数据太水了,所以$O(n^3\log m)$的做法也是可以通过本题的。(其实可以自己做一个链的数据卡掉它)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 2510
using namespace std;
int head[N] , to[N] , next[N] , cnt , si[N] , w[N] , v[N] , n;
double a[N] , mid , f[N][N];
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void init(int x)
{
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i]) init(to[i]) , si[x] += si[to[i]];
}
void dfs(int x)
{
int i , j , k , tot = 0 , b = 0;
memset(f[x] , 0xc2 , sizeof(f[x]));
if(x) f[x][1] = a[x] , tot ++ , b ++ ;
else f[x][0] = 0;
for(i = head[x] ; i ; i = next[i])
{
dfs(to[i]);
for(j = tot ; j >= b ; j -- )
for(k = 1 ; k <= si[to[i]] ; k ++ )
f[x][j + k] = max(f[x][j + k] , f[x][j] + f[to[i]][k]);
tot += si[to[i]];
}
}
int main()
{
int n , k , i , x , c = 30;
double l = 0 , r = 0;
scanf("%d%d" , &k , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d%d%d" , &w[i] , &v[i] , &x) , add(x , i) , r = max(r , (double)v[i]);
init(0);
while(c -- )
{
mid = (l + r) / 2;
for(i = 1 ; i <= n ; i ++ ) a[i] = v[i] - mid * w[i];
dfs(0);
if(f[0][k] >= 0) l = mid;
else r = mid;
}
printf("%.3lf\n" , (l + r) / 2);
return 0;
}
【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp的更多相关文章
- BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)
题目链接 \(Description\) 每个点有费用si与价值pi,要求选一些带根的连通块,总大小为k,使得 \(\frac{∑pi}{∑si}\) 最大 \(Solution\) 01分数规划,然 ...
- BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包)
BZOJ4753: [Jsoi2016]最佳团体(分数规划+树上背包) 标签:题解 阅读体验 BZOJ题目链接 洛谷题目链接 具体实现 看到分数和最值,考虑分数规划 我们要求的是一个\(\dfrac{ ...
- LUOGU P4322 [JSOI2016]最佳团体(0/1分数规划+树形背包)
传送门 解题思路 一道0/1分数规划+树上背包,两个应该都挺裸的,话说我常数为何如此之大..不吸氧洛谷过不了啊. 代码 #include<iostream> #include<cst ...
- [JSOI2016]最佳团体 DFS序/树形DP
题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...
- bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)
菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...
- [Jsoi2016]最佳团体 BZOJ4753 01分数规划+树形背包/dfs序
分析: 化简一下我们可以发现,suma*ans=sumb,那么我们考虑二分ans,之后做树形背包上做剪枝. 时间复杂度证明,By GXZlegend O(nklogans) 附上代码: #includ ...
- BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)
看到比值先二分答案.于是转化成一个非常裸的树形背包.直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对.这里使用一种更通用的dfs序优化树形背包写法.https://www.cnb ...
- bzoj4753[JSOI2016]最佳团体
题意:01分数规划,但可选的数字之间存在森林形的依赖关系(可以认为0号点是个虚根,因为并不能选). 虽然有森林形的依赖关系,但还是可以套分数规划的思路,二分答案k,判断是否存在一个比值大于k的方案 即 ...
- bzoj 4753 最佳团体 —— 01分数规划+树形背包
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4753 注意赋初值为 -inf: eps 设为 1e-3 会 WA ... 代码如下: #in ...
随机推荐
- 协议学习之 vamei博客系列 总结
1. 分层: 物理层(physical layer) 所谓的物理层,是指光纤.电缆或者电磁波等真实存在的物理媒介.这些媒介可以传送物理信号,比如亮度.电压或者振幅.对于数字应用来说,我们只需要两种物理 ...
- oracle的clob转换varchar2
time: 2008/02/29 author: skate oracle的clob转换varchar2 今天在做一个表的数据转移的时候,发现要他通过比较clob字段,但大家都知道clob字段是无法比 ...
- poi实现Excel输出
/** * 第一个demo 导出Excel文件 * 第一行 第三个单元格中 写入 zhangsan */ @Test public void test1() throws IOException { ...
- Bootstrap 徽章(Badges)
本章将讲解Bootstrap徽章(Badges),徽章与标签相似,主要的区别是徽章的圆角比较圆滑. 徽章(Badges)主要用于突出显示新的或未读的项,如果使用徽章,只需要把<span clas ...
- Object类 任何类都是object类的子类 用object对象接收数组 object类的向上向下转型
任何类都是object类的子类 用object对象接收数组 object类的向上向下转型
- linux系统下的用户文件句柄数限制
linux系统下的用户文件句柄数限制 文章来源:企鹅号 为什么要修改用户打开的文件数 系统默认单个进程可以打开1024个文件,对于一些应用如tomcat.oracle等,运行时经常open成千上万个文 ...
- php进行文件的强制下载
浏览器下载文件,例如在浏览器中可以直接打开的文件(.gif /.txt等).在进行文件下载操作时,默认是通过浏览器直接打开,而不是下载保存文件.并且通过这种方法下载文件可以不暴漏下载文件所在的路径,可 ...
- 如何用纯 CSS 创作一个文本淡入淡出的 loader 动画
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/ERwpeG 可交互视频 ...
- DeepFaceLab小白入门(5):训练换脸模型!
训练模型,是换脸过程中最重要的一部分,也是耗时最长的一部分.很多人会问到底需要多少时间?有人会告诉你看loss值到0.02以下就可以了.我会告诉你,不要看什么数值,看预览窗口的人脸.看第二列是否和第一 ...
- 在ArchLinux、manjaro中安装MySql(mariaDB)
安装MySql数据库.但是在MySql被Oracle收购之后,很多开源支持者就转而使用MariaDb了.不过MariaDb也和MySql兼容的,所以基本不用有什么担心.由于ArchLinux只带了Ma ...