首页 > 其他分享 >洛谷P2015 二叉苹果树

洛谷P2015 二叉苹果树

时间:2022-11-26 19:23:22浏览次数:52  
标签:结点 ch 洛谷 int P2015 保留 二叉 110 树枝

sloj P10153. 「一本通 5.2 例 1」二叉苹果树

P2015 二叉苹果树

题目描述

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

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

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

2   5
 \ / 
  3   4
   \ /
    1

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

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

输入格式

第一行2个整数N和Q,分别表示表示树的结点数,和要保留的树枝数量。

接下来N−1行,每行3个整数,描述一根树枝的信息:前2个数是它连接的结点的编号,第3个数是这根树枝上苹果的数量。

输出格式

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

输入输出样例

输入 #1
5 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

相关文章

  • 数据结构实验(五)二叉树
    6-1二叉树的遍历就是简单的遍历voidInorderTraversal(BinTreeBT){if(BT==NULL)return;if(BT->Left!=NULL)InorderTraversal(BT->Left);......
  • 每日算法之重建二叉树
    JZ7重建二叉树描述给定节点数为n的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,......
  • 102. 二叉树的层序遍历
    102.二叉树的层序遍历给你二叉树的根节点root,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。示例1:输入:root=[3,9,20,null,null,15,7]输出:[[3],......
  • 洛谷 P4018 Roy&October之取石子
    洛谷P4018Roy&October之取石子题意:\(n\)个石头,每次取\(p^k\)个石子(\(p\)是质数,\(k\in\N\)),取完最后一个的人获胜,问谁有必胜策略。只能说,MO题真的猛!结论:\(n\bmod......
  • 二叉树的度
    二叉树结点的度(分支度)指该节点引出的边数(节点下面的边)。二叉树结点有3种可能的度:度为0,为叶子节点。度为1,只有左子树或者右子树的节点。度为2,有左右节点的节点。......
  • PHP基于非递归方式算法实现先序/中序/后序遍历二叉树操作
    /** *PHP基于非递归方式算法实现先序/中序/后序遍历二叉树操作 *     A *    B   C *  D  E F   G......
  • leetcode 104. 二叉树的最大深度 js实现
    给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。示例:给定二叉树 [3,9,20,null,null......
  • 洛谷P1090 Java
    [NOIP2004提高组]合并果子/[USACO06NOV]FenceRepairG题目描述在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的......
  • 二叉树
    一、基本概念二叉树的性质:性质1:一棵非空二叉树的第i层上至多有2i-1个结点(i>1)。性质2:深度为h的二叉树至多有2h-1个结点(h>1)。(证明):根据性质1,二叉树中所有节点数为20+21+.........
  • 洛谷P2141 [NOIP2014 普及组] 珠心算测验
    [NOIP2014普及组]珠心算测验题目描述珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而......