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 ---------- */