• timus_1018_dp


    二叉苹果树

      题目意思: 有一个二叉树,每个树枝都有若干个苹果,现在要保留一些树枝,把其它的树枝删掉,问这棵树最多能保留多少个苹果?

      输入:第一行有两个数N和Q,N(2 ≤ N ≤ 100; 1 ≤ Q ≤ N − 1)代表二叉树中结点的个数,Q代表保留的树枝的个数。接下来的N-1行描述二叉树的边,每条边包含两个结点和边上苹果的数量。端点是按1,2,3...N编号的,1代表根结点,删除的树枝中不能包含根结点。

      输出:在保留的树枝中苹果的最大数量

      样例输入:

      5 2

      1 3 1

      1 4 10

      2 3 20

      3 5 20

      样例输出:

      21

     

    思路:

      这是一个用树状dp来解决的问题,对于dp,当然是找到状态转移方程和状态的表示,而对于树状dp中的树,指的是在状态转移的时候,必须根据树的性质来,而不像一般的dp。我用dp[k][r]表示以k为树根的子树保留r条边的的最大苹果数,那么状态转移方程为:

    状态的转移可以用类似于树的后续遍历来做。

    源代码:

     

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 #define max(a, b) (a > b ? a : b)
     5 typedef struct _tree_t
     6 {
     7     int n;
     8     struct _tree_t *left, *right;
     9     int lapple, rapple;
    10 }tree_t;
    11 
    12 int n, q;
    13 int edge[101][101];
    14 int dp[101][101];
    15 
    16 
    17 void BuildTree(int x, tree_t **root)
    18 {
    19     int i;
    20 
    21     *root = (tree_t *)malloc(sizeof(tree_t));
    22     (*root)->n = x;
    23     (*root)->left = NULL;
    24     (*root)->right = NULL;
    25     for (i = 2; i <= n; i ++)
    26         if (edge[x][i])
    27         {
    28             (*root)->lapple = edge[x][i];
    29             edge[x][i] = edge[i][x] = 0;
    30             BuildTree(i, &((*root)->left));
    31             break;
    32         }
    33     for (i ++; i <= n; i ++)
    34         if (edge[x][i])
    35         {
    36             (*root)->rapple = edge[x][i];
    37             edge[x][i] = edge[i][x] = 0;
    38             BuildTree(i, &((*root)->right));    
    39             break;
    40         }
    41 }
    42 void Print(tree_t *root)
    43 {
    44     if (root == NULL)
    45         return;
    46     printf("%d ", root->n);
    47     Print(root->left);
    48     Print(root->right);
    49 }
    50 
    51 int TreeDp(tree_t *root)
    52 {
    53     int i, j, r1 = 0, r2 = 0;    
    54 
    55     if (root->left == NULL && root->right == NULL)
    56     {
    57         dp[root->n][0] = 0;
    58         return 0;
    59     }
    60     if (root->left)
    61         r1 = TreeDp(root->left);
    62     if (root->right)
    63         r2 = TreeDp(root->right);
    64     for (i = 0; i <= r1; i ++)
    65         for (j = 0; j <= r2 && i + j <= q; j ++)
    66         {
    67             if (root->right && i + j + 1 <= q)
    68                 dp[root->n][i + j + 1] = max(dp[root->right->n][j] + root->rapple, dp[root->n][i + j + 1]);
    69             if (root->left && i + j + 1 <= q)
    70                 dp[root->n][i + j + 1] = max(dp[root->left->n][i] + root->lapple, dp[root->n][i + j + 1]);
    71             if (root->left && root->right && i + j + 2 <= q)
    72                 dp[root->n][i + j + 2] = max(dp[root->left->n][i] + root->lapple + dp[root->right->n][j] + root->rapple, dp[root->n][i + j + 2]);
    73         }
    74             
    75     if (root->left == NULL)    
    76         return r2 + 1;
    77     if (root->right == NULL)
    78         return r1 + 1;
    79     return r1 + r2 + 2;
    80 }
    81 
    82 int main ( int argc, char *argv[] )
    83 {
    84     int i, e1, e2, apple;
    85     tree_t *root = NULL;
    86 
    87     scanf("%d%d", &n, &q);
    88     for (i = 0; i < n - 1; i ++)
    89     {
    90         scanf("%d%d%d", &e1, &e2, &apple);    
    91         edge[e1][e2] = apple;
    92         edge[e2][e1] = apple;
    93     }
    94     BuildTree(1, &root);
    95 //    Print(root);
    96     TreeDp(root);    
    97     printf("%d\n", dp[1][q]);
    98     return 0;
    99 }                /* ----------  end of function main  ---------- */
  • 相关阅读:
    nodejs 核心模块crypto
    es6新特性学习
    nodejs 常用全局包
    ionic+angular+cordova 安卓环境搭建
    谷歌浏览器调试保存到文件
    Linux命令
    Linux中用户管理详解(上)-Linux学习日记
    liunx下忘记root密码的解决方法
    cvCanny的参数
    VC运行时库(/MD、/MT等)
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/3088214.html
Copyright © 2020-2023  润新知