zoukankan      html  css  js  c++  java
  • POJ 2486 Apple Tree 树形DP

    题意:给一棵树,每个节点都有一个权值,权值只能拿一次,只让走K步,问最多能拿到多少权值

    这个题目一开始没料到原来可以往回走,分析了样例才知道。之后我用DFS搜索,超时

    后来一直想树形DP的状态转移,一直没想出来。后来还是看别人博客上的状态转移方程。

    dp[0][rt][j+2]=max(本身,dp[0][rt][w]+dp[0][nx][j-w])//w为枚举的需要多少步,由于要从nx子节点返回,故需要比j多两步

    dp[1][rt][j+2]=max(本身,dp[1][rt][w]+dp[0][nx][j-w])//走向子树后回来再一去不回,因为从子树回来需要多走两步

    dp[1][rt][j+1]=max(自身,dp[1][nx][w]+dp[0][rt][j-w])//走向其他地方回来再走向子树一去不回,走子树只需要多一步

    一开始没怎么理解,后来想通了,每次是枚举一个子树,已经枚举好的子树已经找到最佳状态,就是上面所谓的最佳状态,尚未枚举的子树暂且当做不存在

    因为暂且未枚举的子树需要当做不存在,就要用到背包,从倒序循环步数,来保证当前找到的最佳,一定是该子树之前那个状态再加当前状态,我一开始正序循环步数,就像完全背包一样,同在一个状态里面,造成了干扰。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    vector<int> v[105];
    int n,k;
    int val[105];
    int dp[2][105][205];
    int vis[105];
    void clean(int n)
    {
        for (int i=0;i<=n;i++)
            v[i].clear();
    }
    void dfs(int rt)
    {
        vis[rt]=1;
        int r=v[rt].size();
        for (int i=0;i<r;i++){
            int nx=v[rt][i];
            if (vis[nx]) continue;
            dfs(nx);
            for (int j=k;j>=0;j--){
               for (int w=0;w<=j;w++){
                if (dp[0][rt][j+2]<dp[0][rt][j-w]+dp[0][nx][w])
                    dp[0][rt][j+2]=dp[0][rt][j-w]+dp[0][nx][w];
    
                if (dp[1][rt][j+2]<dp[1][rt][j-w]+dp[0][nx][w])
                    dp[1][rt][j+2]=dp[1][rt][j-w]+dp[0][nx][w];
    
                if (dp[1][rt][j+1]<dp[1][nx][w]+dp[0][rt][j-w])
                    dp[1][rt][j+1]=dp[1][nx][w]+dp[0][rt][j-w];
    
               }
            }
        }
    }
    int main()
    {
        while (scanf("%d%d",&n,&k)!=EOF)
        {
            clean(n);
            int i,j;
            for (i=1;i<=n;i++)
                scanf("%d",&val[i]);
            for (j=1;j<n;j++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                v[a].push_back(b);
                v[b].push_back(a);
            }
            memset(vis,0,sizeof vis);
            for (i=0;i<=n+5;i++){
                for (j=0;j<=k+5;j++){
                    dp[0][i][j]=val[i];
                    dp[1][i][j]=val[i];
                }
            }
            dfs(1);
            int ans=0;
            ans=max(dp[0][1][k],dp[1][1][k]);
            printf("%d
    ",dp[1][1][k]);
        }
        return 0;
    }

    关于为什么最后最佳状态是dp[1][1][k]而不是dp[0][1][k],我也不是很理解,不过我想这样说可能说得通,如果是dp[0][1][k],则最后一步肯定是回到原点,这样没有对结果又任何贡献,最多也是==前者,所以最后最优结果应该是前者

  • 相关阅读:
    NodeJS系列~第一个小例子,实现了request.querystring功能
    JS~js里实现队列与堆栈
    最新CSS兼容方案
    js传真实地址 C:fakepath
    IE11的变化 navigator.userAgent中不再包含“MSIE”关键字
    看看该死的jquery.form.js的用法,不是个东西
    bootstrap模态框怎么传递参数
    方法的直接调用,反射调用
    IIS 7.5 配置伪静态
    TrippleDESCSPEncrypt 加密解密试试看
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3404922.html
Copyright © 2011-2022 走看看