树形背包 学习笔记
时间:2021-10-03
本文章向大家介绍树形背包 学习笔记,主要包括树形背包 学习笔记使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
发现树形背包又忘掉了。。。所以来复习一下顺便写博客。
朴素的树形背包是定义\(f(i,j)\)表示以i为子树用j重量时的最大价值。
那么我们再枚举给每一颗子树分配多少重量,这就是和背包类似的方法了。
#include <cstdio>
#include <algorithm>
using std::max;
const int N = 3e2 + 10, M = 3e2 + 10;
int n, m, f[N][N], s[N], son[N][N];
void dfs (int u) {
for (int i = 1; i <= son[u][0]; ++i) {
int v = son[u][i]; dfs(v);
for (int j = m + 1; j >= 1; --j)
for (int k = 0; k < j; ++k)
f[u][j] = max(f[u][j], f[u][j - k] + f[v][k]);
}
}
int main () {
scanf ("%d%d", &n, &m);
for (int i = 1, fa; i <= n; ++i) {
scanf ("%d%d", &fa, s + i);
f[i][1] = s[i];
son[fa][++son[fa][0]] = i;
}
dfs(0);
printf ("%d\n", f[0][m + 1]);
return 0;
}
上述代码来自https://www.cnblogs.com/water-mi/p/9818622.html
这是一种比较好的写法,我们先把\(f(i,weight[i])\)预处理出来,以后直接使用,避免麻烦的处理过程!!!!!!!
不过注意当前点u至少要分配weight[u]的重量,转移的时候需要注意,否则会出现不选当前点就选子树的错误。
但是还可以优化,利用dfs序。
可以考虑如果选当前节点,那么它可以更新f(i+1),否则它直接更新f(nex[i]),其中nex[i]为i的下一个兄弟的dfs序。
这里如果考虑f(i,0/1)为当前选和不选转移稍微有点麻烦。我们可以用一个比较好的优化方法,即f(i)表示前i-1个点做完决策时的最大收益,转移的时候更新到f(i+1)的时候再加上第i个点的收益。可以令nex[n]=n+1,这样最后的答案即为f(n+1)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 9, M = 1e4 + 9;
int n, m, w[N], v[N];
struct Edge{
int v;
Edge *nxt;
} e[N];
Edge *head[N];
int e_cnt;
void addEdge(int u, int v){
e[++e_cnt] = Edge {v, head[u]};
head[u] = &e[e_cnt];
}
int dfn[N], nx[N], ttime, id[N], f[N][M];
void dfs(int u){
dfn[u] = ttime;
id[ttime] = u;
ttime++;
for(Edge *i = head[u]; i != NULL; i = i -> nxt)
dfs(i -> v);
nx[dfn[u]] = ttime;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1, fa; i <= n; ++i){
scanf("%d%d%d", w + i, v + i, &fa);
if(fa == i) fa = 0;
addEdge(fa, i);
}
dfs(0);
for(int i = 2; i <= n + 1; ++i)
for(int j = 0; j <= m; ++j)
f[i][j] = -1e9;
for(int u = 1; u <= n; ++u){
int wt = w[id[u]], vl = v[id[u]];
for(int j = 0; j <= m; ++j)
f[nx[u]][j] = std::max(f[nx[u]][j], f[u][j]);
for(int j = 0; j <= m - wt; ++j)
f[u + 1][j + wt] = std::max(f[u + 1][j + wt], f[u][j] + vl);
}
printf("%d\n", f[n + 1][m]);
}
上述代码利用ttime的操作也令了nex[n]=n+1
原文地址:https://www.cnblogs.com/lytql/p/15365204.html
- 纳税服务系统七(投诉管理模块)【显示投诉信息、处理回复、我要投诉、Quartz自动受理、统计图FusionCharts】
- Unikernel初体验
- Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、
- Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、
- Scala学习教程笔记一之基础语法,条件控制,循环控制,函数,数组,集合
- Kafka的生产者和消费者代码解析
- Caused by: java.lang.ClassNotFoundException: backtype.storm.topology.IRichSpout
- 作为完美主义者(强迫症)如何将linux的eth1网卡修改为eth0网卡
- 【入门篇】一个小白在Jetson TX2上安装caffe的踩坑之旅
- 【入门篇】Jetson TX2深度学习Inference初体验
- zeromq的安装,部署(号称最快的消息队列,消息中间件)
- OpenDaylight新建HelloWorld工程并集成版本
- 摸索出来的chrom调试前后台数据(Java&&Ajax)交互的方法分享一下咯!!!
- 机器学习:单词拼写纠正器python实现
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法