• POJ 2486 Apple Tree(树形DP)


    题目链接

    树形DP很弱啊,开始看题,觉得貌似挺简单的,然后发现貌似还可以往回走...然后就不知道怎么做了...

    看看了题解http://www.cnblogs.com/wuyiqi/archive/2012/01/09/2316758.html画画题解中的三种情况,还是可以理解的。

    设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 <iostream>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 200100
    #define LL __int64
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    struct node
    {
        int u,v,next;
    }edge[201];
    int dp[201][201][2];
    int first[201];
    int p[201];
    int t,n,k;
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
        memset(dp,0,sizeof(dp));
    }
    void add(int u,int v)
    {
        edge[t].u = u;
        edge[t].v = v;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    void dfs(int rt)
    {
        int i,j,son,v;
        for(i = 0;i <= k;i ++)
        dp[rt][i][0] = dp[rt][i][1] = p[rt];
        for(i = first[rt];i != -1;i = edge[i].next)
        {
            son = edge[i].v;
            dfs(son);
            for(j = k;j >= 0;j --)
            {
                for(v = 0;v <= j;v ++)
                {
                    dp[rt][j+2][0] = max(dp[rt][j+2][0],dp[rt][v][0]+dp[son][j-v][0]);
                    dp[rt][j+1][1] = max(dp[rt][j+1][1],dp[rt][v][0]+dp[son][j-v][1]);
                    dp[rt][j+2][1] = max(dp[rt][j+2][1],dp[rt][v][1]+dp[son][j-v][0]);
                }
            }
        }
    }
    int main()
    {
        int i,u,v;
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            CL();
            for(i = 1;i <= n;i ++)
            scanf("%d",&p[i]);
            for(i = 1;i < n;i ++)
            {
                scanf("%d%d",&u,&v);
                add(u,v);
            }
            dfs(1);
            printf("%d
    ",dp[1][k][1]);
        }
        return 0;
    }
  • 相关阅读:
    ubuntu 安装FoxitReader福昕阅读器(转载)
    添加中文字库
    操作系统常用调度算法(转载https://www.cnblogs.com/kxdblog/p/4798401.html)
    2802:小游戏利用bfs来实现
    2802:小游戏
    适合使用并行的一种bfs
    (转载)关于usr/bin/ld: cannot find -lxxx问题总结
    gcc5.4报错对‘std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()’未定义的引用
    centos7如何安装gcc5.4
    将含有makefile文件的源码加入Eclipse工程
  • 原文地址:https://www.cnblogs.com/naix-x/p/3203949.html
Copyright © 2020-2023  润新知