洛谷 P2015 二叉苹果树 && caioj1107 树形动态规划(TreeDP)2:二叉苹果树
这道题一开始是按照caioj上面的方法写的
(1)存储二叉树用结构体,记录左儿子和右儿子
(2)把边上的权值转化到点上,离根远的点上
(3)用记忆化搜索,枚举左右节点分别有多少个点,去递归
这种写法有个好处, 避免了总的树枝个数的枚举
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int MAXN = 112;
struct node
{
int v, w;
node(int v = 0, int w = 0) : v(v), w(w) {}
};
struct tree
{
int l, r;
tree() { l = r = 0; }
}a[MAXN];
vector<node> g[MAXN];
int f[MAXN][MAXN], n, q;
void dfs(int x, int fa)
{
REP(i, 0, g[x].size())
{
int v = g[x][i].v, w = g[x][i].w;
if(v == fa) continue;
f[v][1] = w;
if(!a[x].l) a[x].l = v;
else a[x].r = v;
dfs(v, x);
}
}
int tree_dp(int x, int k)
{
if(x == 0) return 0;
if(f[x][k] != -1) return f[x][k];
int maxt = 0;
REP(i, 0, k)
{
int ls = i, rs = k - i - 1;
maxt = max(maxt, f[x][1] + tree_dp(a[x].l, ls) + tree_dp(a[x].r, rs));
}
return f[x][k] = maxt;
}
int main()
{
scanf("%d%d", &n, &q);
REP(i, 0, n - 1)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(node(v,w));
g[v].push_back(node(u,w));
}
memset(f, -1, sizeof(f));
dfs(1, -1);
REP(i, 1, n + 1) f[i][0] = 0;
f[1][1] = 0;
printf("%d\n", tree_dp(1, q + 1));
return 0;
}
然后看到洛谷上还有更加简洁的写法
先往下搜索,然后回溯的时候记录边的数量,然后枚举左右节点
取多少树枝,取max。
f[u][j] = max(f[u][j-k-1] + f[v][k] + w);
然后这里用到了01背包的思想
树枝可以看成从的总的重量,所以要逆序
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int MAXN = 112;
struct node
{
int v, w;
node(int v = 0, int w = 0) : v(v), w(w) {}
};
vector<node> g[MAXN];
int f[MAXN][MAXN], b[MAXN], n, q;
void dfs(int u, int fa)
{
REP(i, 0, g[u].size())
{
int v = g[u][i].v, w = g[u][i].w;
if(v == fa) continue;
dfs(v, u);
b[u] += b[v] + 1;
for(int j = min(q, b[u]); j >= 0; j--)
for(int k = 0; k <= min(b[v], j - 1); k++)
f[u][j] = max(f[u][j], f[u][j-k-1] + f[v][k] + w);
}
}
int main()
{
scanf("%d%d", &n, &q);
REP(i, 1, n)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(node(v,w));
g[v].push_back(node(u,w));
}
dfs(1, 0);
printf("%d\n", f[1][q]);
return 0;
}
做完了选课在来看这一题,又有新的感悟。
树上背包的做法适用于多叉树和二叉树,二叉树是两个物品,多叉树是多个物品。
而这道题有一点不同是权值是边。那么吸取上面写的经验。
我们可以把边的权值转移到离根远的点上,同时可以取的点数为边数+1
然后就一样啦!!
#include<cstdio>
#include<vector>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int MAXN = 112;
int f[MAXN][MAXN], n, q;
struct node
{
int v, w;
node(int v = 0, int w = 0) : v(v), w(w) {}
};
vector<node> g[MAXN];
int dfs(int u, int fa)
{
int sum = 1;
REP(i, 0, g[u].size())
{
int v = g[u][i].v, w = g[u][i].w;
if(v == fa) continue;
f[v][1] = w;
int t = dfs(v, u);
sum += t;
for(int j = sum; j >= 1; j--)
for(int k = 0; k <= min(t, j - 1); k++)
f[u][j] = max(f[u][j], f[u][j-k] + f[v][k]);
}
return sum;
}
int main()
{
scanf("%d%d", &n, &q);
REP(i, 0, n - 1)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(node(v, w));
g[v].push_back(node(u, w));
}
dfs(1, -1);
printf("%d\n", f[1][q+1]);
return 0;
}
洛谷 P2015 二叉苹果树 && caioj1107 树形动态规划(TreeDP)2:二叉苹果树的更多相关文章
- 洛谷 P1273 有线电视网 && caioj 1109 树形动态规划(TreeDP)4:比赛转播(树上分组背包总结)
从这篇博客往前到二叉苹果树都可以用分组背包做 这依赖性的问题,都可以用于这道题类似的方法来做 表示以i为根的树中取j个节点所能得的最大价值 那么每一个子树可以看成一个组,每个组里面取一个节点,两个节点 ...
- 洛谷 P2015 二叉苹果树 (树上背包)
洛谷 P2015 二叉苹果树 (树上背包) 一道树形DP,本来因为是二叉,其实不需要用树上背包来干(其实即使是多叉也可以多叉转二叉),但是最近都刷树上背包的题,所以用了树上背包. 首先,定义状态\(d ...
- 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门
dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...
- 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP
题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...
- 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)
洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...
- 洛谷 P7163 - [COCI2020-2021#2] Svjetlo(树形 dp)
洛谷题面传送门 神仙级别的树形 dp. u1s1 这种代码很短但巨难理解的题简直是我的梦魇 首先这种题目一看就非常可以 DP 的样子,但直接一维状态的 DP 显然无法表示所有情况.注意到对于这类统计一 ...
- DP,数论————洛谷P4317 花神的数论题(求1~n二进制中1的个数和)
玄学代码(是洛谷题解里的一位dalao小粉兔写的) //数位DP(二进制)计算出f[i]为恰好有i个的方案数. //答案为∏(i^f[i]),快速幂解决. #include<bits/stdc+ ...
- 动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序
洛谷P4017 最大食物链计数 这是洛谷一题普及/提高-的题目,也是我第一次做的一题 图上动态规划/拓扑排序 ,我认为这题是很好的学习拓扑排序的题目. 在这题中,我学到了几个名词,入度,出度,及没有环 ...
- NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序
原文链接https://www.cnblogs.com/zhouzhendong/p/9258043.html 题目传送门 - 洛谷P3953 题目传送门 - Vijos P2030 题意 给定一个有 ...
随机推荐
- swift中高阶函数map、flatMap、filter、reduce
Swift相比于Objective-C又一个重要的优点,它对函数式编程提供了很好的支持,Swift提供了map.filter.reduce这三个高阶函数作为对容器的支持. 1 map:可以对数组中的每 ...
- SpringCloud学习笔记(1)----认识微服务与SpringCloud
1. 微服务是什么? 微服务是一种由多个服务组成的集合体,它属于一种软甲架构,在微服务中,它的每个服务都是独立存在的,微服务是一种去中心化的思想. 它具有开发简单,技术栈灵活,服务独立解耦,可用性高 ...
- 《Unix环境高级编程》读书笔记 第3章-文件I/O
1. 引言 Unix系统的大多数文件I/O只需用到5个函数:open.read.write.lseek以及close 本章描述的函数经常被称为不带缓冲的I/O.术语不带缓冲指的是在用户的进程中对其不会 ...
- while循环,格式化输出%,运算符,数据类型的转换,编码的初识,
1.内容总览 while循环 格式化输出 运算符 and or not 编码的初识 2. 具体内容 while 循环 where:程序中:你需要重复之前的动作,输入用户名密码时,考虑到while循环. ...
- mariadb数据库基础知识及备份
数据库介绍 1.什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来管理 ...
- ERROR in xxxx.js from UglifyJS——配置版本混杂版
常规解决套路可以参考这篇:https://segmentfault.com/a/11... 我采用了上面的做法,依然没法解决.我采用的是vue-cli脚手架自动生成的项目结构: vue-cli版本 2 ...
- Mac安装软件时,提示文件已损坏,需要移动到废纸篓的解决方法
1.修改系统偏好设置,安全性与隐私-->将“允许从以下位置下载的应用” ☑️任何来源. 2. mac10.12以上的系统一般没有“任何来源”这个选项,需打开terminnal终端,输入 sudo ...
- [转载]深入Java单例模式
在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在 ...
- redis为什么选择单线程工作模型
1.先说一下为什么出现进程,线程 进程:在计算机发明之初就发现,在输入数据时(I/O速度慢),CPU是空闲的,这样就浪费了CPU资源,为了充分利用CPU资源,发明了进程,在输入程序A的数据时,程序B在 ...
- [数位dp] bzoj 3209 花神的数论题
题意:中文题. 思路:和普通数位dp一样,这里转换成二进制,然后记录有几个一. 统计的时候乘起来就好了. 代码: #include"cstdlib" #include"c ...