树形背包O(n * v^2)入门
我虽然做了好几道树形背包的题,但是一直不是十分理解,对于每一道题,总是看题解就明白,然后换一道题自己写不出来。临近NOIP,gg让我们强化一下背包以及树形背包,我也恰有此打算,于是又开始从头学习了树形背包。
看了好多博客以及论文之后,对树形背包确实有了一个全新的认识,尤其是这篇博客以及徐持恒的论文《浅谈积累背包问题》,对我有很大的帮助。两者都提到了泛化物品(当然这个名词最初是在背包九讲里面提到的)这个概念,我觉得这是对树形背包O(n * v2)做法的一种不同理解,不过我认为引入这个名词的主要目的还是对O(nv)的做法做出了解释。遗憾的是,我虽然用O(nv)的做法成功写出了一道题,然而却仍旧不是很懂。所以这篇博文主要是讲解O(n * v2)的做法,也算是整理自己的学习笔记吧。
如果哪一天我把O(nv)的做法看懂了的话,可能还会来更这篇博客。
上文已经提到,对于O(n * v2)的做法有两种不同的理解,那么我在这里就分别阐述一下。
都以这道题为例
一、用分组背包来理解
首先题中给的依赖关系是一个森林,那么可以建立一个虚拟节点0,作为森林的根,形成一棵树。
令dp[u][j]表示以 u 为根的子树中,选 j 门课(体积)能得到的最大学分。那么 u 一定要选(初始化dp[u][1] = val[u]),而对于子树内其他点的选取情况,可以把每一种选取方案看成一个物品,又因为每一种方案都是互斥的,每一组只能选一个,那么就是一个分组背包了。这里的组数,是 u 的儿子个数 p = |son(u)|,对于一个vi ∈son(u),他其实代表了j - 1个物品(因为还要选u),拿其中一个为例,dp[vi][k](0 <= k < j)这种选取方案才代表一个物品。
现在考虑转移方程。按照分组背包的写法,我们应该先加一维,dp[u][k][j]表示以x为根的子树,选到第k组,选了 j 门课得到的最大学分。于是有dp[u][k][j] = max(dp[u][k - 1][j], dp[u][k - 1][j - h] + dp[v][sz][h])。注意,dp[v][sz][h]代表一个物品,sz是v的所有组数,因为要保证最优,所以一定从v的所有组数选完的状态转移到u。
然后再模仿分组背包省去第二维,把 j 倒着枚举。
核心代码:
void dfs(int now)
{
for(int i = head[now]; i; i = e[i].nxt)
{
dfs(e[i].to);
for(int j = m + ; j; --j)
for(int k = ; k < j; ++k) //这一维正着倒着都行,有很多书上是倒着的
dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[e[i].to][k]);
}
}
对于每一个节点只会进行一次O(v2)的分组背包,所以复杂度O(n * v2)。
二、用泛化物品来理解
首先得解释一下啥叫泛化物品:一个价值随体积改变而改变的物品,而且对于一个体积 i,有对应的v[i]。
这个其实人人都见过,只不过没有听说这个名词而已。比如求解01背包就是泛化一个物品的过程,得到的dp[i]就是一个泛化物品。
还有这么回事,泛化物品的和 :有两个泛化物品G1[i], G2[i],要将这两个物品合并。做法就是对于每一个体积 i ,枚举分配给这两个物品的体积 j ,G[i] = max{G1[j], G2[i - j]}。复杂度O(v2)。
现在用泛化物品的概念看看树形背包。dp[u][j]表示的是u所在的泛化物品,则从子树向上递归的时候,其实就是不断地将u所在的泛化物品和他的子树vi的泛化物品合并。合并一次的复杂度O(v2),一共n各节点,每合并一次减少一个,所以总复杂度还是O(n * v2)。
代码和上面完全相同,因为这本来就是对树形背包的两种理解,而不是两种写法。
void dfs(int now)
{
for(int i = head[now]; i; i = e[i].nxt)
{
dfs(e[i].to);
for(int j = m + ; j; --j)
//倒着枚举,因为左边的dp[now][j]代表新的物品,右边的dp[now][j]是原来的物品
for(int k = ; k < j; ++k) //枚举分配体积
dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[e[i].to][k]);
}
}
树形背包O(n * v2)的做法到此也基本讲完了,但这其实都是基础,深入的话还是得靠自己刷题去“悟”。还有一点就是如果哪位大佬会O(nv)的做法,能不能给我讲讲……
树形背包O(n * v^2)入门的更多相关文章
- poj 1155 TELE (树形背包dp)
本文出自 http://blog.csdn.net/shuangde800 题目链接: poj-1155 题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构, ...
- poj2486Apple Tree[树形背包!!!]
Apple Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9989 Accepted: 3324 Descri ...
- cdoj 1136 邱老师玩游戏 树形背包
邱老师玩游戏 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1136 Desc ...
- HDU 1011 树形背包(DP) Starship Troopers
题目链接: HDU 1011 树形背包(DP) Starship Troopers 题意: 地图中有一些房间, 每个房间有一定的bugs和得到brains的可能性值, 一个人带领m支军队从入口(房 ...
- bzoj 4813: [Cqoi2017]小Q的棋盘 [树形背包dp]
4813: [Cqoi2017]小Q的棋盘 题意: 某poj弱化版?树形背包 据说还可以贪心... #include <iostream> #include <cstdio> ...
- [HAOI2015]树上染色(树形背包)
有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之间的距离加 ...
- Luogu 1273 有线电视网 - 树形背包
Description 树形背包, 遍历到一个节点, 枚举它的每个子节点要选择多少个用户进行转移. Code #include<cstring> #include<cstdio> ...
- BZOJ2427: [HAOI2010]软件安装 tarjan+树形背包
分析: 一开始我以为是裸的树形背包...之后被告知这东西...可能有环...什么!有环! 有环就搞掉就就可以了...tarjan缩点...建图记得建立从i到d[i]之后跑tarjan,因为这样才能判断 ...
- BZOJ 2427 [HAOI2010]软件安装 | 这道树形背包裸题严谨地证明了我的菜
传送门 BZOJ 2427 题解 Tarjan把环缩成点,然后跑树形背包即可. 我用的树形背包是DFS序上搞的那种. 要注意dp数组初始化成-INF! 要注意dp顺推的时候也不要忘记看数组是否越界! ...
随机推荐
- 登陆oracle数据库时提示“ORA-28002: 7 天之后口令将过期” 或提示 密码过期
登陆oracle数据库时提示“ORA-28002: 7 天之后口令将过期” 或提示 密码过期. [原因/触发因素] 确定是由于oracle11g中默认在default概要文件中设置了“PASSWORD ...
- 一:SpringMVC架构流程
架构流程: 1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用HandlerMapping处理器映射器. 3.处理器映射器根据请求url ...
- 流畅的python和cookbook学习笔记(二)
1.元组拆包和解压序列赋值 任何的序列 (或者是可迭代对象) 可以通过一个简单的赋值语句解压并赋值给多个 变量.唯一的前提就是变量的数量必须跟序列元素的数量是一样的. 1.平行赋值: >> ...
- java.lang.RuntimeException: Canvas: trying to draw too large(107331840bytes) bitmap.
环境: Android 8.0.1 MIUI 真机测试闪退 gradle 4.1 compileSdkVersion 26 buildToolsVersion '26.0.2' minSdkVersi ...
- spring实现固定时间定时器
此文章是基于 搭建Jquery+SpringMVC+Spring+Hibernate+MySQL平台 一. jar包介绍 1. spring-framework-4.3.4.RELEASE 的 lib ...
- new date()标准时间转yyyy-mm-dd hh:mm 24小时制
<!DOCTYPE html> <html> <head> <title>new date()标准时间转yyyy-mm-dd hh:mm 24小时制&l ...
- java-IO小记
说来惭愧,工作一年多了,对io仍然不是很了解.不仅是io,还有网络,还有多线程.shame!!! 接下来的日子里,先搞多线程,再搞io,再搞网络,半年内一定要完成! 好了,今天终于搞懂了outputS ...
- 车厢调度(train.cpp)
车厢调度(train.cpp) [问题描述] 有一个火车站,铁路如图所示,每辆火车从A驶入,再从B方向驶出,同时它的车厢可以重新组合.假设从A方向驶来的火车有n节(n<=1000) ...
- 【Android】10.0 UI开发——如何编写程序界面、常见控件的使用
************************ 转载请注明出处:https://www.cnblogs.com/xiaofu007/p/10331880.html ***************** ...
- Cookie实现留言板
Cookie实现留言板 直接代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content- ...