洛谷 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 题意 给定一个有 ...
随机推荐
- 51nod 1267 4个数和为0 思路:哈希map+避免重复的点
题目: 总结大佬们的思路: 思路1:所有数两两求和,存入map中,每次判断有没有相反数被标记过. 思路2:对所有数排序,排完所有数两两求和,结果正好是排好序的.然后扫一遍,二分查找看之前有没有相反数存 ...
- js闭包的用途详解
js闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中 我们来看看闭包的用途.事实上,通过使用闭包,我们可以做很多事情.比如模拟 ...
- 【原创】VMWare克隆或复制Linux虚拟机后无法上网的解决
如果选择桥接,需要设置网卡通过哪个物理网卡桥接,桥接代表当前虚拟机通过本机的网卡直接连到网络中,本机网卡作为一个交换机直连.因此需要确定使用哪个网卡桥接,一般在单网卡的时候选择自动即可,多网卡时需要指 ...
- 【原创】关于not in的一些事情
早上到公司,收到一条cocall消息,是某哥们遇到的疑惑,可能很多新手并不知情: 请教个问题 我执行 . select * from t_htgl_htpswj t where t.c_wjmc = ...
- jQuery获取单选框(复选框)选中的状态
jQuery 获取单选框(复选框)选中的状态 <input type="checkbox" name="" id="choose"/& ...
- MyBatis中关于SQL标签的用法(重用SQL 代码段)
一. 没用sql标签前的SQL映射代码: <select id="findById" resultType="cn.tedu.mybatis.entity.User ...
- OSI概述问答
1. 网络中体系结构的七层.四层.五层是怎么回事? OSI(Open System Interconnection)开放系统互连参考模型的七层协议体系结构:概念清楚,理论比较完整,但既复杂又不用 ...
- 利用php的GD库生成验证码
<?php ,); //创建一个100宽30高的底图,默认黑色 ,,); //修改颜色.数字对应 rgb 的三个数值.白色 imagefill(,,$bgcolor); //从左上角到右下角把颜 ...
- HDU-3416 Marriage Match IV 最短路+最大流 找各最短路的所有边
题目链接:https://cn.vjudge.net/problem/HDU-3416 题意 给一个图,求AB间最短路的条数(每一条最短路没有重边.可有重复节点) 思路 首先把全部最短路的边找出来,再 ...
- 关于.net core 在docker中监听地址设置踩坑记
1.今天在做docker容器的时候发现如果将.net core 内部监听地址设置为localhost:8888. 2.在docker build -p 6444:8888 运行容器后,外部通过6444 ...