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  ---------- */
posted @ 2013-05-23 16:21  在于思考  阅读(566)  评论(0编辑  收藏  举报