【树形DP】POJ 2486 Apple Tree

通道:http://poj.org/problem?id=2486

题意:点权树,求从1出发,走V步,最多能遍历到的点权和

思路:

我们把背包的思想用到这里来,做的步数相当于背包的容量,点上的权值相当于价值,给定一定的背包容量,求最多能装进背包的       价值

      设dp[0][s][j]表示从s(当前根节点)出发,走 j 步,回到s所能获得的最大权值

      dp[1][s][j]表示从s(当前根节点)出发,走j步,不回到s所能获得的最大权值

      现在我们就可以分配背包容量了:父节点与子节点分配背包容量,从而设计出状态转移方程

      主要思想:

      s返回,t返回   

      s不返回,t返回(走向t子树,t子树返回之后走向s的其他子树,然后不回到s)

      s返回,t不返回(遍历s的其他子树后返回s,返回之后走向t子树,然后不回到t)

      没有都不返回,肯定有一方有一个返回的过程,再去另一边的子树的

     总结起来一句话,要么去s的其他子树呆着,要么去t子树呆着,要么回到s点
图片 

      1、在t子树返回,其他子树也返回,即回到当前根节点s

      2,、不返回根节点,但在t子树返回,即相当于从t出发走k步返回t的最优值  加上  从s出发走j-k步到其他子树不返回的最优值,中间有s      与t连接起来,其实就等于从s出发遍历t子树后(dp[0][t][k])又回到s(这一步多了中间的来回两步),再走出去(其他子树)【dp[1]      [s][j-k]】,不回来

     3、不返回根节点,在t子树也不返回,等价于从s出发遍历其他子树,回到s(dp[0][s][j-k]),再走向t子树,不回到t(dp[1][t]              [k]),这个过程s-t只走了一步

      dp[0][s][j+2]=Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);//从s出发,要回到s,需要多走两步s-t,t-s,分配给t子树k步,其      他子树j-k步,都返回
      dp[1][s][j+2]=Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);//不回到s(去s的其他子树),在t子树返回,同样有多出两步
      dp[1][s][j+1]=Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);//先遍历s的其他子树,回到s,遍历t子树,在当前子树t不返回,      多走一步

代码:

 

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int MAX_N = 101;

int n, k;
int val[MAX_N];
int dp[2][MAX_N][201];

vector<int> edge[MAX_N];

void addedge(int u, int v) {
    edge[u].push_back(v);
}

void init() {
    memset(dp, 0, sizeof dp);
    for (int i = 0; i < MAX_N; ++i) {
        edge[i].clear();
    } 
}

void dfs(int u, int fa) {
    for (int i = 0; i <= k; ++i) {
        dp[0][u][i] = dp[1][u][i] = val[u];
    }
    for (int i = 0; i < edge[u].size(); ++i) {
        int v = edge[u][i];
        if (v == fa) continue;
        dfs(v, u);
        for (int j = k; j >= 0; --j) {
            for (int l = 0; l <= j; ++l) {
                dp[0][u][j + 2] = max(dp[0][u][j + 2], dp[0][v][l] + dp[0][u][j - l]);
                dp[1][u][j + 2] = max(dp[1][u][j + 2], dp[0][v][l] + dp[1][u][j - l]);
                dp[1][u][j + 1] = max(dp[1][u][j + 1], dp[0][u][j - l] + dp[1][v][l]);
            }
        }
    }
}

int main() {
    while (2 == scanf("%d%d", &n, &k)) {
        init();
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &val[i]);
        }
        for (int i = 1; i < n; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        dfs(1, -1);
        printf("%d\n", dp[1][1][k]);
    }
    return 0;
}
View Code

 

posted @ 2014-11-03 19:43  mithrilhan  阅读(188)  评论(0编辑  收藏  举报