zoukankan      html  css  js  c++  java
  • POJ 2486 apple tree(树形dp)

    题意:

    一棵树,每个节点有一个权值,求从根节点出发,最多走K步,能够取得的最大权值(可以往回走)。

    思路:

    dp[1][u][j]  从u节点出发,最多走j步(可以小于j步),并且返回到 u 节点,可以获得的最大权值。

    dp[0][u][j] 从u节点出发,最多走j步,最终停留在u的子树节点,可以获得的最大权值。

    关键是状态转移方程啊,涉及到停留在 u 点和停留在 v 点展开了优化讨论:

    dp[1][u][i+2] = max(dp[1][u][i+2], dp[1][v][i-j] + dp[1][u][j]);
    dp[0][u][i+2] = max(dp[0][u][i+2], dp[1][v][i-j] + dp[0][u][j]);
    dp[0][u][i+1] = max(dp[0][u][i+1], dp[0][v][i-j] + dp[1][u][j]);

    其中v是u节点的孩子节点,j range from K to 0(类似01背包)

    代码中使用了一点小小的剪枝:由于没走到一个孩子节点,步数至少减少 1 的,所以可以逐步把步数减 1,最终代码跑到了 32ms.

    
    
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 110;
    const int MAXD = 210;
    
    structedge {
        int v;
        edge* next;
    } *V[MAXN], ES[MAXN * 2];
    
    int EC, N, K, val[MAXN], dp[2][MAXN][MAXD];
    bool vis[MAXN];
    
    void addedge(int u, int v)
    {
        ES[++EC].next = V[u];
        V[u] = ES + EC; V[u]->v = v;
    }
    
    void initdata(int n)
    {
        EC = 0;
        memset(V, 0, sizeof(V));
        memset(vis, false, sizeof(vis));
    
        for (int i = 1; i <= n; ++i)
            scanf("%d", &val[i]);
    
        for (int i = 1; i <= n - 1; ++i)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }
    }
    
    void treedp(int u, int vol)
    {
        vis[u] = true;
    
        for (int j = 0; j <= vol; ++j)
            dp[0][u][j] = dp[1][u][j] = val[u];
    
        for (edge* e = V[u]; e; e = e->next)
        {
            int v = e->v;
            if (vis[v])
                continue;
    
            treedp(v, vol - 1);
    
            for (int i = vol; i >= 0; --i)
            {
                for (int j = 0; j <= i; ++j)
                {
                    dp[1][u][i+2] = max(dp[1][u][i+2], dp[1][v][i-j] + dp[1][u][j]);
                    dp[0][u][i+2] = max(dp[0][u][i+2], dp[1][v][i-j] + dp[0][u][j]);
                    dp[0][u][i+1] = max(dp[0][u][i+1], dp[0][v][i-j] + dp[1][u][j]);
                }
            }
        }
    }
    
    int main()
    {
        while (scanf("%d %d", &N, &K) != EOF)
        {
            initdata(N);
            treedp(1, K);
            printf("%d\n", dp[0][1][K]);
        }
        return 0;
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    函数递归,匿名函数
    生成器
    迭代器
    有参函数(认证功能)
    闭包函数和装饰器
    文件处理
    Celery介绍
    Redis 介绍
    GIT知识点
    前后端分离-前端配置
  • 原文地址:https://www.cnblogs.com/kedebug/p/2761123.html
Copyright © 2011-2022 走看看