• $Luogu$ $P1040$ 加分二叉树


    链接

    背景

    (CCF) (NOIP2003) (T3)(Luogu) (P1040)

    题意

    设一棵二叉树(形态未知)的中序遍历是 ({ 1,2,3,cdots,n }) 。给定这 (n) 个节点的权值,规定一棵子树的得分是左右子树得分之积加上根节点权值的结果。请构造出一棵满足题意的树使得得分最大,并求出最大得分和树的先序遍历。注意叶节点的得分是本身权值,仅有一棵子树的节点另一棵空子树得分记为 (1)

    解法

    不是树形 (dp) 模板。是习题。
    然而我死活想不出解。后来发现我把中序遍历和先序遍历搞混淆了。
    由于构造出来的树要满足中序遍历的要求,则选定 (x) 点为子树 ([l,r]) 的根之后左子树只能为 ([l,x-1]) ,右子树只能为 ([x+1,r]) 。于是就有了最优子结构性质。
    (f_{l,r}) 表示中序遍历是 ({ l,l+1,l+2,cdots,r }) 的子树的最大得分。则转移应当枚举其中的一个点作为这棵子树的根,再递归计算左右子树的值。
    于是考虑记忆化搜索(本质是动态规划的递归实现形式),状态转移是 (f_{l,r}=max_limits{k in [l,r]} { f_{l,k-1} imes f_{k+1,r}+val_k }) 。要求的就是 (f_{l,r})
    最后考虑怎么输出先序遍历。由于先根、后左子、最后右子,于是在 (dp) 的时候可以给每棵子树 ([l,r]) 确定一个根节点 (root_{l,r}) ,做完之后从 ([1,n]) 开始递归输出即可,先输出根节点,再递归左子树,最后递归右子树。

    细节

    (1.) 两个边界:子树为空(即 (l>r) )时显然得分只能为 (0) ;子树仅有一个节点(即 (l=r) ,是一个叶节点)时显然得分就是本身权值。

    (2.) 注意输出时为了避免递归不停止,在子树为空(即 (l>r) )时直接 (return)

    $View$ $Code$ ```cpp #include using namespace std; inline int read() { int ret=0,f=1; char ch=getchar(); while('9'ans) { ans=nowans; anspos=i; } } rt[l][r]=anspos; return f[l][r]=ans; } void print(int l,int r) { if(r
  • 相关阅读:
    C#控件刷新
    [转载] 尺度不变特征变换匹配算法
    C++ windows 多线程 互斥锁
    堆栈内存申请,以及32位程序内存上限
    dumpbin检查Dll
    CV_Assert
    Linux复习
    操作系统复习
    P/NP问题
    程序
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11838643.html
Copyright © 2020-2023  润新知