2 条题解

  • 0
    @ 2025-10-8 16:49:12
    #include <bits/stdc++.h> 
    using namespace std;
    int f[31][31], root[31][31];
    //动态规划的核心是理解好数据结构的表示意义
    //f[i][j]表示如果第i个节点至第j个节点的所有点成为一个树,那么最大得分是多少
    //root[i][j] 表示如果第i个节点至第j个节点的所有点成为一个树,那么根节点是谁 
    int d[31];
    void pre_dfs(int l, int r)//  对 从l到r的所有点 进行 先序遍历
    {
        if(l <= r)
        {
            printf(" %d", root[l][r]);                     //先写中间
            pre_dfs(l, root[l][r]-1);//  对左子树先序遍历
            pre_dfs(root[l][r]+1, r);//  对右子树先序遍历
        }
    }
     
    int main()
    {
        int n; scanf("%d", &n);
        for(int i=0; i <= n; i++)for(int j=0; j <= n; j++) f[i][j] = 1;//一般初始化都为0,为什么这里为1
        for(int i=1; i <= n; i++)
        {
            scanf("%d", &d[i]);
            root[i][i] = i;//一开始假设每个点最不济的情况就是叶子节点,那么它就是自己这个范围[i,i]的树的根(只有一个点) 
            f[i][i] = d[i];//一开始,每个点的加分只有自己的分值 
        }
        for(int k=2; k <= n; k++) // 枚举形式不唯一,但我喜欢从规模小打规模大
            for(int L=1; L <= n-k+1; L++)// 确定了长度为k,那么枚举开头L
            {
                int R = L + k - 1; //左边开始端点是L,长度为k,那么右边就是 L+k-1 
                for(int mid = L; mid <= R; mid++)// 枚举中间点 mid,mid就是 i到j所有点的根
                {
                    if(f[L][R] < f[L][mid-1] * f[mid+1][R] + d[mid])
                    {
                        f[L][R] = f[L][mid-1] * f[mid+1][R] + d[mid];//既然可以更新,那就是比以前的好,那么要及时记录
                        root[L][R] = mid;  //记录L到R这一段此刻之所以变得更大,是因为选中了mid作为这些点的根 
                    }
                }
            }
        printf("%d\n", f[1][n]);
        //下面开始打印先序遍历的结果了 
        printf("%d", root[1][n]);
        pre_dfs(1, root[1][n]-1);
        pre_dfs(root[1][n]+1, n); 
        return 0;
    }
    
    • 0
      @ 2025-10-8 16:48:58
      #include<bits/stdc++.h> 
      using namespace std;
      int f[31][31],root[31][31];
      //动态规划的核心是理解好数据结构的表示意义
      //f[i][j]表示如果第i个节点至第j个节点的所有点成为一个树,那么最大得分是多少
      //root[i][j] 表示如果第i个节点至第j个节点的所有点成为一个树,那么根节点是谁 
      int d[31];
      void pre_dfs(int l,int r)//  对 从l到r的所有点 进行 先序遍历
      {
          if(l<=r)
          {
              printf(" %d",root[l][r]);                     //先写中间
              pre_dfs(      l         ,   root[l][r]-1    );//  对左子树先序遍历
              pre_dfs( root[l][r]+1   ,        r          );//  对右子树先序遍历
          }
      }
       
      int main()
      {
          int n; scanf("%d",&n);
          for(int i=0;i<=n;i++)for(int j=0;j<=n;j++) f[i][j]=1;//一般初始化都为0,为什么这里为1
          for(int i=1;i<=n;i++)
          {
              scanf("%d",&d[i]);
              root[i][i]=i;//一开始假设每个点最不济的情况就是叶子节点,那么它就是自己这个范围[i,i]的树的根(只有一个点) 
              f[i][i]=d[i];//一开始,每个点的加分只有自己的分值 
          }
          for(int k=2;k<=n;k++) // 枚举形式不唯一,但我喜欢从规模小打规模大
              for(int L=1;L<=n-k+1;L++)// 确定了长度为k,那么枚举开头L
              {
                  int R=L+k-1; //左边开始端点是L,长度为k,那么右边就是 L+k-1 
                  for(int mid=L;mid<=R;mid++)// 枚举中间点 mid, mid就是 i到j所有点的根
                  {
                      if( f[L][R] < f[L][mid-1] * f[mid+1][R] +d[mid] )
                      {
                          f[L][R] = f[L][mid-1] * f[mid+1][R] +d[mid];//既然可以更新,那就是比以前的好,那么要及时记录
                          root[L][R]=mid;  //记录L到R这一段此刻之所以变得更大,是因为选中了mid作为这些点的根 
                      }
                  }
              }
          printf("%d\n",f[1][n]);
          //下面开始打印先序遍历的结果了 
          printf("%d",root[1][n]);
          pre_dfs(1,root[1][n]-1);
          pre_dfs(root[1][n]+1,n); 
          return 0;
      }
      • 1

      *【动态规划:区间中间推】[NOIP 2003 提高组] 加分二叉树

      信息

      ID
      23
      时间
      1000ms
      内存
      128MiB
      难度
      5
      标签
      递交数
      145
      已通过
      52
      上传者