POJ-2486 Apple Tree 树形DP
这题和POJ1947类似, 同样是树形DP, 就是因为按照上题的思路写, 导致写的是非常的蛋疼. 调了几小时还是无果. 时候证明还是对状态的意义理解的不透彻.
设dp[x][0][j]表示以节点x为根至多走j步并且返回x处所能够得到的最多苹果.
dp[x][1][j]表示以节点x为根至多走j步不需要返回x处所能够得到的最多苹果.
那么就可以得到动态转移方程(此时的dp[x][..][j]还没有完善, 需要后期处理一下):
dp[x][0][j] = max( dp'[x][0][j-m] + dp[v][0][m] ); 0<=m<=j 其中dp'表示计算到上一个孩子节点为止, v是x的孩子节点
dp[x][1][j] = max( dp'[x][1][j-m] + dp[v][0][m], dp'[x][0][j-m] + dp[v][1][m] ) 0<=m<=j
此时的dp[x][..][j] 并没有计算本身这个节点的权值, 并且进入这个节点同样有距离开销, 因此程序在实现的时候有一个平移更新状态的过程.
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #include <iostream> using namespace std; /* 题意:给定一棵长满苹果的树, 告诉我们每个节点上有多少个苹果, 现在某人从1这个节点出 发, 最多走K步的情况下, 最多能够得到多少苹果. 解法: */ struct Node { int v, next; }e[105]; int N, S, G[105][105], apple[105], vis[105]; int head[105], idx, ch[105], dp[105][2][205]; void insert(int a, int b) { ++idx; e[idx].v = b, e[idx].next = head[a]; head[a] = idx; } void visit(int x) { vis[x] = 1; for (int i = 1; i <= N; ++i) { if (!vis[i] && G[x][i]) { insert(x, i); ++ch[x]; visit(i); } } } void dfs(int x) { if (head[x] == -1) { // 如果该点位叶子节点 return; } int temp[2][205] = {0}, v; for (int i = head[x]; i != -1; i = e[i].next) { dfs(v = e[i].v); for (int j = S; j >= 2; j--) { dp[v][0][j] = dp[v][0][j-2]+ apple[v]; } dp[v][0][1] = dp[v][0][0] = dp[v][1][0] = 0; for (int j = S; j >= 1; j--) { dp[v][1][j] = dp[v][1][j-1]+ apple[v]; } for (int j = 0; j <= S; ++j) { for (int m = 0; m <= j; ++m) { temp[0][j] = max(temp[0][j], dp[x][0][j-m] + dp[v][0][m]); temp[1][j] = max(temp[1][j], dp[x][0][j-m] + dp[v][1][m]); temp[1][j] = max(temp[1][j], dp[x][1][j-m] + dp[v][0][m]); } } memcpy(dp[x], temp, sizeof (temp)); } } int main() { int x, y; while (scanf("%d %d", &N, &S) == 2) { idx = -1; memset(dp, 0, sizeof (dp)); memset(head, 0xff, sizeof (head)); memset(G, 0, sizeof (G)); memset(ch, 0, sizeof (ch)); memset(vis, 0, sizeof (vis)); for (int i = 1; i<= N; ++i) { scanf("%d", apple+i); } for (int i = 1; i < N; ++i) { scanf("%d %d", &x, &y); G[x][y] = G[y][x] = 1; } visit(1); // 建立一棵从1为根的有根树 dfs(1); printf("%d\n", dp[1][1][S] + apple[1]); } return 0; }