zoukankan      html  css  js  c++  java
  • POJ2486 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;    
    }
  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/Lyush/p/2865439.html
Copyright © 2011-2022 走看看