这道题一开始是按照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:二叉苹果树的更多相关文章

  1. 洛谷 P1273 有线电视网 && caioj 1109 树形动态规划(TreeDP)4:比赛转播(树上分组背包总结)

    从这篇博客往前到二叉苹果树都可以用分组背包做 这依赖性的问题,都可以用于这道题类似的方法来做 表示以i为根的树中取j个节点所能得的最大价值 那么每一个子树可以看成一个组,每个组里面取一个节点,两个节点 ...

  2. 洛谷 P2015 二叉苹果树 (树上背包)

    洛谷 P2015 二叉苹果树 (树上背包) 一道树形DP,本来因为是二叉,其实不需要用树上背包来干(其实即使是多叉也可以多叉转二叉),但是最近都刷树上背包的题,所以用了树上背包. 首先,定义状态\(d ...

  3. 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门

    dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...

  4. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  5. 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)

    洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...

  6. 洛谷 P7163 - [COCI2020-2021#2] Svjetlo(树形 dp)

    洛谷题面传送门 神仙级别的树形 dp. u1s1 这种代码很短但巨难理解的题简直是我的梦魇 首先这种题目一看就非常可以 DP 的样子,但直接一维状态的 DP 显然无法表示所有情况.注意到对于这类统计一 ...

  7. DP,数论————洛谷P4317 花神的数论题(求1~n二进制中1的个数和)

    玄学代码(是洛谷题解里的一位dalao小粉兔写的) //数位DP(二进制)计算出f[i]为恰好有i个的方案数. //答案为∏(i^f[i]),快速幂解决. #include<bits/stdc+ ...

  8. 动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序

    洛谷P4017 最大食物链计数 这是洛谷一题普及/提高-的题目,也是我第一次做的一题 图上动态规划/拓扑排序 ,我认为这题是很好的学习拓扑排序的题目. 在这题中,我学到了几个名词,入度,出度,及没有环 ...

  9. NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序

    原文链接https://www.cnblogs.com/zhouzhendong/p/9258043.html 题目传送门 - 洛谷P3953 题目传送门 - Vijos P2030 题意 给定一个有 ...

随机推荐

  1. jqGrid冻结列

    jqgrid冻结列 冻结列:就是横向移动表格时,让某一列保持不动 做法: 1.colModel的行要加上属性: frozen:true.注意:冻结列必须从第一列开始,包括隐藏列 2.加载jqgrid后 ...

  2. bioinformaitcs的latex版本参考文献填坑

    最近实验室投bioinfomatics的刊,编辑说要把参考文献的格式改成不带方括号的,而且加点,而且只保留前三作者,之后用et al. 折腾了一下午,终于弄出来了. 首先,导言区需要添加: \make ...

  3. PostgreSQL+PostGIS

    PostGIS简介 PostGIS是对象关系型数据库系统PostgreSQL的一个扩展,PostGIS提供如下空间信息服务功能:空间对象.空间索引.空间操作函数和空间操作符.同时,PostGIS遵循O ...

  4. ActiveMQ学习笔记(2)----JMS的基本概念和模型

    1. JMS 的基本概念 1. JMS是什么? JMS Java Message Service,Java消息服务,是Java EE中的一种技术. 2. JMS规范 JMS定义了Java中访问消息中间 ...

  5. Vue中路由的使用

    在Vue中动态挂载组件 首先需要安装  cnpm install vue-router --save 在main.js中引入VueRouter 并使用 定义一个路由 创建router实例 通过rout ...

  6. js去掉字符串得第一个字符 、去掉字符串的最后一个字符

    a1 = aa[0].slice(1);  //去掉第一个字符串 a2 = a2.substr(0, a2.length - 1);

  7. python 面向对象 类方法,静态方法,property

    property 内置装饰器函数 只在面向对象使用 把方法当初属性使用(方法不加参数) 例子: class Rectangle: def __init__(self,long,wide,color): ...

  8. 如何配置任意目录下Web应用程序

    1,首先创建一个Web项目,tomcat 7, JDK 1.8 2,创建Web项目并部署到tomcat服务器下运行的步骤和方法: 在Eclipse下创建一个JAVA project 在JAVA项目下创 ...

  9. 仿百度排列图片预览插件-Simple Lightbox

    很久以前遇到过这样的一个面试题,要求手写代码,实现百度图片的排列预览,并且可以左右点击查看下一张照片,当时没有做出来,这个问题也就一直放在了脑后,工作之后,遇到这样的需求之后,第一反应想到的是在源码网 ...

  10. 兼顾php和jquery新版本的checkbox的写法

    <input type="checkbox" class="scate_item" name="scategories[]" valu ...