• 加分二叉树


    原题链接:https://www.luogu.org/problem/show?pid=1040

    刚拿到这道题的我是懵逼的,因为刚开始除了暴力我完全想不到从哪入手。

    其实这题是一个区间dp和dfs,代码还是挺简单的。

    参考了一篇题解,对那位大佬表示由衷的敬意。

    设f[i][j]表示在区间(i,j)内的最大加分,那么有f[i][j] = max(f[i][k-1]*f[k+1][j]+a[k]) ,a[k]代表第i个点的分数,k是枚举的根节点,即状态转移方程的那个式子是指的在区间(i,j)上的以k为根节点的最大分数。

    还记得区间dp的基本思路吗?由小区间推出大区间,这题也是这样,i从n倒推至1,j从i正推至n,而中间的枚举根节点k的范围是[i,j]。

    同时我们还需要一个数组n[i][j]表示在区间(i,j)加分最大时的根节点,在后面会用到。

    最高加分便是f[1][N]。//为了不和n数组重复用一个大写

    考虑下一个问题,如何输出一棵树的前序遍历?

    还记得什么是前序遍历吗?先根,再左子树,再右子树。

    要输出一个遍历,递归输出就好。首先输出当前的点(根节点),然后输出左子树,再输出右子树,简单的划分。

    参考代码:

     1 #include <iostream>
     2 #define maxn 35
     3 using namespace std;
     4 int a[maxn];
     5 int N;
     6 int f[maxn][maxn];
     7 int n[maxn][maxn];
     8 
     9 
    10 void dfs(int l,int r){
    11     if (l>r)
    12         return;
    13     int mid = n[l][r];
    14     cout << mid << " ";
    15     dfs(l,mid-1);
    16     dfs(mid+1,r);
    17 }
    18 
    19 int main(){
    20     cin >> N;
    21     for (int i=0;i<=N;i++)
    22         for (int j=0;j<=N;j++)
    23             f[i][j] = 1;
    24 
    25     for (int i=1;i<=N;i++){
    26         cin >> a[i];
    27         f[i][i] = a[i];
    28         n[i][i] = i;
    29     }
    30 
    31     for (int i=N-1;i>=1;i--)
    32         for (int j=i+1;j<=N;j++)
    33             for (int k=i;k<=j;k++)
    34                 if (f[i][k-1]*f[k+1][j]+a[k]>f[i][j]){
    35                     n[i][j]=k;
    36                     f[i][j]=f[i][k-1]*f[k+1][j]+a[k];
    37                 }
    38     cout << f[1][N] << endl;
    39     dfs(1,N);
    40 
    41     return 0;
    42 }
  • 相关阅读:
    找水王续
    找水王续
    本周学习进度
    Node.js 学习
    在Linux机器上安装MySQL
    ZStack串口通信
    Java编写串口程序
    ServerSocket
    ZigBee毕设
    ZigBee相关网站链接
  • 原文地址:https://www.cnblogs.com/OIerShawnZhou/p/7589419.html
Copyright © 2020-2023  润新知