题目描述

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入输出格式

输入格式:

第1行2个数,N和Q(1<=Q<= N,1<N<=100)。

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式:

一个数,最多能留住的苹果的数量。

输入输出样例

输入样例#1

5 2

1 3 1

1 4 10

2 3 20

3 5 20

输出样例#1

21

算法:

树形DP

 

分析:

这道题其实是要我们计算在一棵二叉树上保留一定数量的枝条情况下的最大权值。

这是一个基础的树形DP模板题,在二叉树上进行动规。我们发现对于树上的任意一棵子树,它的根节点和两个子树存在着关系,我们探究一下,树是由递归性质得到的,所以我们首先要把我们得到的数据先在一个数组上建造出来。

 

把树建好了之后,我们就可以探究它的状态转移方程,我们已知n-1条边,为了方便,我们把它设为双向的边。我设len[x][y]和len[y][x]表示x到y的边上权值为len[x][y](或len[y][x])。

接下来,设num[v]表示以v为子节点的那条边的长度,设f[v][k]为以v为根节点的子树中保留k条边的最大权值,设tr[v][ans]为以v为根节点的左右儿子分别是什么,当ans表示1时,他是左儿子,反之,则为右儿子。

 

把一棵树放到一个线性DP里面想的话,就会容易多了。我要求当前的f[v][k],我首先要求得他的左右儿子分担一共k条边的最大值分别是什么,然后相加即可。

 

可列得状态转移方程为:f[v][k]=max(f[v][k],f[tr[v][1]][i]+f[tr[v][2]][k-i-1]+num[v]);

 

这个东西相信不难看懂,接下来我们需要优化程序。既然树可以递归来建造,那么我们是不是也可以用递归来求解呢?嗯,是可以的。

这是我们就可以将普通的DP放到DFS上做,合成了记忆化搜索。因为有一些枝条我在之前已经计算过了,那么我可以直接拿来用。

 

说几点注意的,最后输出答案要输出q+1的情况,因为在计算过程中我们为了方便,将边的问题都转化成父节点或者是子节点问题,所以需要我们在节点数上再+1。

切记len数组要初始化一个负数,在用完其中一条边时,记得把那条边和另外一条等价的边都给删掉。

 

上代码:

 #include<cstdio>
#include<iostream>
using namespace std; int n,q,tr[][],num[],len[][],f[][]; //数据规模不大,int 型已经足够 inline int read() //读入优化
{
int x=,f=;
char c=getchar();
while (c<||c>)
f=c=='-'?-:,c=getchar();
while (c>=&&c<=)
x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
} void buildtree(int v) //建树
{
int i,ans=;
for (i=;i<=n;i++)
if (len[v][i]>=) //有分叉
{
ans++; //记录并判断左右子树
tr[v][ans]=i;
num[i]=len[v][i]; //记录长度
len[v][i]=len[i][v]=-; //删除两条边
buildtree(i); //递归它的孩子节点
if (ans==) //到了就返回
return;
}
} void dfs(int v,int k) //记忆化搜索
{
if (k==) //边界
f[v][k]=;
else
if (tr[v][]==&&tr[v][]==) //到了叶子节点,其值等于原值
f[v][k]+=num[v];
else
{
f[v][k]=; //先清零
int i,j;
for (i=;i<k;i++) //枚举0到k-1的情况
{
if (!f[tr[v][]][i]) //左儿子记忆化
dfs(tr[v][],i);
if (!f[tr[v][]][k-i-]) //右儿子记忆化
dfs(tr[v][],k-i-);
f[v][k]=max(f[v][k],f[tr[v][]][i]+f[tr[v][]][k-i-]+num[v]); //状态转移
}
}
} int main()
{
int i,j;
n=read();
q=read();
for (i=;i<=n;i++) //初始化
for (j=;j<=n;j++)
len[i][j]=-;
for (i=;i<=n-;i++)
{
int x=read(),y=read();
len[x][y]=len[y][x]=read();
}
buildtree(); //建树
dfs(,q+); //求解
printf("%d",f[][q+]); //注意,切记是q+1
return ;
}

这是一道二叉树的基础DP,我感觉挺好理解的,主要的模型就是递归建树+记忆化搜索DP,简单记为2个DFS。

 

 

嗯,就这样了。

【洛谷P2015】二叉苹果树的更多相关文章

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

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

  2. 洛谷p2015二叉苹果树&yzoj1856多叉苹果树题解

    二叉 多叉 有一棵苹果树,如果树枝有分叉,可以是分多叉,分叉数k>=0(就是说儿子的结点数大于等于0)这棵树共有N个结点(叶子点或者树枝分叉点),编号为1~N,树根编号一定是1.我们用一根树枝两 ...

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

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

  4. 洛谷 P2015 二叉苹果树 && caioj1107 树形动态规划(TreeDP)2:二叉苹果树

    这道题一开始是按照caioj上面的方法写的 (1)存储二叉树用结构体,记录左儿子和右儿子 (2)把边上的权值转化到点上,离根远的点上 (3)用记忆化搜索,枚举左右节点分别有多少个点,去递归 这种写法有 ...

  5. 洛谷P2015 二叉苹果树

    题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来 ...

  6. 洛谷 P2015 二叉苹果树

    老规矩,先放题面 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端 ...

  7. 洛谷—— P2015 二叉苹果树

    https://www.luogu.org/problem/show?pid=2015 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点 ...

  8. 洛谷P2015 二叉苹果树(树状dp)

    题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来 ...

  9. 洛谷P2015二叉苹果树

    传送门啦 树形 $ dp $ 入门题,学树形 $ dp $ 的话,可以考虑先做这个题. $ f[i][j] $ 表示在 $ i $ 这棵子树中选 $ j $ 个苹果的最大价值. include #in ...

  10. 洛谷 P2015 二叉苹果树 题解

    题面 裸的树上背包: 设f[u][i]表示在以u为子树的树种选择i条边的最大值,则:f[u][i]=max(f[u][i],f[u][i-j-1]+f[v][k]+u到v的边权); #include ...

随机推荐

  1. 获取emacs安装的elpa包名称

    | grep "./" | sed 's/\.\///g' | sed 's/-[0-9].*$//' | sort -u

  2. 操作系统之实验二Step1-有序顺序表

    实验二Step1-有序顺序表 专业:商业软件工程     班级:商软2班     姓名:甘佳萍     学号:201406114207 实验要求:初始化 输入数组元素个数. 输入n个数,排序输出. 存 ...

  3. selenium 概念及练习 !

    1.selenium中如何判断元素是否存在? 2.selenium中hidden或者是display = none的元素是否可以定位到? 3.selenium中如何保证操作元素的成功率?也就是说如何保 ...

  4. 【vue】this与that 一个坑

    [转载自]:https://blog.csdn.net/qq_30378229/article/details/78429374 在Vue中this始终指向Vue,但axios中this为undefi ...

  5. opencv 矩阵类数据的运算

    参考:http://blog.sina.com.cn/s/blog_7908e1290101i97z.htmlhttp://blog.sina.com.cn/s/blog_afe2af380101bq ...

  6. React安装React Devtools调试工具

    在运行一个React项目的时候浏览器控制台会提醒你去安装react devtools调试工具. Download the React DevTools for a better development ...

  7. Contest 2

    A:辣鸡题.搜索怎么这么难啊.不会啊. B:裸的高斯消元,看起来可以优化到n2. #include<iostream> #include<cstdio> #include< ...

  8. 【刷题】BZOJ 3238 [Ahoi2013]差异

    Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N< ...

  9. 【WebAPI】新手入门WebAPI

    一.前言       工作也有一年多了,从进入公司就一直进行BIM(建筑信息模型)C/S产品的研发,平时写的最多的就是Dev WPF.一个偶然的时机,产品需要做支付宝扫码与微信扫码,所以需要了解产品服 ...

  10. windows内核提权

    Windows by default are vulnerable to several vulnerabilities that could allow an attacker to execute ...