poj 2486
地址:http://poj.org/problem?id=2486
题意:有一颗苹果树,每个节点上面有很多苹果,从一个节点到另外一个可以到达的节点花费1步,求k步最多能吃到多少苹果。
mark:这是典型的回溯型树状dp。dp[i][j][0]代表以i为根节点的子树最多j步后回到i能吃到的最多的苹果,dp[i][j][1]代表以i为根节点的子树最多j步后不回到i节点最多能吃到的子树。那么状态转移就分三步了。
(1)dp[i][j+2][0] = max(dp[i][j+2][0], dp[i][j-k][0]+dp[son][k][0]);
(2)dp[i][j+1][1] = max(dp[i][j+1][1], dp[i][j-k][0]+dp[son][k][1]); 人留在i的子节点son的子树中
(3)dp[i][j+2][1] = max(dp[i][j+2][1], dp[i][j-k][1]+dp[son][k][0]); 人留在不是son的i的子节点的子树中
好好想想状态的转移!
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> const int N = 110; int n,k; int tree[N][N],w[N]; int dp[N][2*N][2]; bool vst[N]; int max(int a, int b) {return a > b ? a : b;} void dfs(int fa) { if(vst[fa]) return ; vst[fa] = 1; int i,j; for(i = 0; i <= k; i++) dp[fa][i][0] = dp[fa][i][1] = w[fa]; for(int p = 1; p <= tree[fa][0]; p++) { if(vst[tree[fa][p]]) continue; dfs(tree[fa][p]); for(i = k; i >= 0; i--) for(j = 0; j <= i; j++) { dp[fa][i+2][0] = max(dp[fa][i+2][0], dp[fa][i-j][0]+dp[tree[fa][p]][j][0]); dp[fa][i+1][1] = max(dp[fa][i+1][1], dp[fa][i-j][0]+dp[tree[fa][p]][j][1]); dp[fa][i+2][1] = max(dp[fa][i+2][1], dp[fa][i-j][1]+dp[tree[fa][p]][j][0]); } } } int main() { int i,j; while(~scanf("%d%d", &n, &k)) { for(i = 1; i <= n; i++) { tree[i][0] = 0; scanf("%d", w+i); } int aa,bb; for(i = 1; i < n; i++) { scanf("%d%d", &aa, &bb); tree[aa][0]++; tree[aa][tree[aa][0]] = bb; tree[bb][0]++; tree[bb][tree[bb][0]] = aa; } memset(vst, 0, sizeof(vst)); dfs(1); printf("%d\n", dp[1][k][1]); } return 0; }