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;    
    }
  • 相关阅读:
    windows8.1专业中文版一个可用的密钥分享
    ARTS打卡计划第四周-TIPS-自定义一个LikeFilter
    ARTS打卡计划第四周-ALGORITHM
    ARTS打卡计划第三周-Share-spring,echart开发统计图的经验
    ARTS打卡计划第三周-Tips
    ARTS打卡计划第三周-Algorithm
    ARTS打卡计划第三周-Review
    ARTS打卡计划第二周-Share-使用java注解对方法计时
    ARTS打卡计划第二周-Tips-mysql-binlog-connector-java的使用
    ARTS打卡计划第二周-Review
  • 原文地址:https://www.cnblogs.com/Lyush/p/2865439.html
Copyright © 2011-2022 走看看