sloj P10153. 「一本通 5.2 例 1」二叉苹果树
P2015 二叉苹果树
题目描述
有一棵苹果树,如果树枝有分叉,一定是分二叉(就是说没有只有一个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1∼N,树根编号一定是1
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
输入格式
第一行2个整数N和Q,分别表示表示树的结点数,和要保留的树枝数量。
接下来N−1行,每行3个整数,描述一根树枝的信息:前2个数是它连接的结点的编号,第3个数是这根树枝上苹果的数量。
输出格式
一个数,最多能留住的苹果的数量。
输入输出样例
输入 #15 2 1 3 1 1 4 10 2 3 20 3 5 20输出 #1
21
说明/提示
1<=Q<N<=100,每根树枝上的苹果<=3×104。
我乍一看,貌似可以记忆化搜索,嗯对,确实可以
不过呢,我想作死挑战极限,所以我就写了个极其让人秃头普通的树形dp
本题权值在边上,这对思考问题有些别扭,其实只要把边的权值转移到儿子结点上,问题仍然性质不变。 需要保留的树枝数量为 M 条,即保留结点数目 j=M+1 个。树根必须保留,可以分三种情况讨论: • 树根的左子树为空,全部保留右子树,右子树中保留 j-1 个结点;这种可以合并到第三种 • 树根的右子树为空,全部保留左子树,左子树中保留 j-1 个结点;这种也可以合并到第三种 • 树根的两棵子树非空,设左子树保留 k 个结点,则右子树保留 j-k-1 个结点。就这种有用 前两种情况就是第三种取k=j时和k=0时,但是分三种对于后面简单一点 很明显,要想保留树根时的苹果数最大,只需要求出上述三个方案中的最大值即可。 设树根为 i,左儿子为 ch[i][0], 右儿子为 ch[i][1]; 对于 (1) 方案,要取得该方案的最大值,需要取得以 ch[i][1] 为根,保留 j-1 个结点的最大值。 这时同样具有上述三种方案。 其他 (2)(3) 情况同理; 由此可以看出,该问题具有明显的最优子结构性质,每个问题都与左右儿子结点有关系,但 不与孙子结点发生关系,具备无后效性;且计算方案时,搜索子结构时具备重叠性,可以用动态规划来解决。 看了算法标签之后才想到的 设 f[i,j] 表示以 i 为根的子树上保留 j 个节点时最多能保留的苹果数量。设 ch[i,0],ch[i,1] 分别为i 节点的左右孩子。 状态转移方程:这不难吧,狗头保命 f[i, j] = max{f[ch[i, 0], k] + f[ch[i, 1], j − k − 1] + a[i]}(0 <= k <= j − 1) 初始化:f[i,j]=0;(j=0,即表示以 i 为根选 0 个结点); f[i,j]=a[i];(ch[i,0]=0 且 ch[i,1]=0, 即叶子结点时) Answer=f[1,M+1]; 注意:本题知道根为 1;若不知道根结点需要枚举根节点,再建立树; 那么又到了你们最喜欢的环节 上 代 码#include<bits/stdc++.h> using namespace std; int n,q,g[110][110],ch[110][10],f[110][110],a[110]; void dfs(int x){ for(int i = 1;i<=n;i++){ if(g[x][i]>=0){ if(!ch[x][0]){ ch[x][0] = i; a[i] = g[x][i]; g[i][x] = g[x][i] = -1; dfs(ch[x][0]); }else{ ch[x][1] = i; a[i] = g[x][i]; g[i][x] = g[x][i] = -1; dfs(ch[x][1]); } } } } int dp(int i,int j){ if(i==0||j==0) return 0; if(ch[i][0]==0&&ch[i][1]==0) return a[i]; if(f[i][j]>0) return f[i][j]; for(int k = 0;k<j;k++) f[i][j] = max(f[i][j],dp(ch[i][0],k)+dp(ch[i][1],j-k-1)+a[i]); return f[i][j]; } int main(){ scanf("%d%d",&n,&q); q++; for(int i = 1;i<=n;i++) for(int j = 1;j<=n;j++) g[i][j] = -1; for(int i = 1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); g[x][y] = g[y][x] = z; } dfs(1); printf("%d",dp(1,q)); return 0; }
标签:结点,ch,洛谷,int,P2015,保留,二叉,110,树枝 From: https://www.cnblogs.com/cztq/p/16928102.html