POJ 2486--Apple Tree

32 篇文章 0 订阅
29 篇文章 0 订阅

题意:有一颗苹果树,每个节点有一些苹果,问从根节点出发走K步最多能吃到多少苹果。

题解:树形DP,状态转移较为复杂,具体可参考注释。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;

class solve
{
private:
    vector<vector<int> > sons;
    char* vis;
    int** dp[2];
    int N,K;
    int maxVal;
public:
    solve(int n,int k):N(n),K(k)
    {
        sons.resize(N+1);
        vis = new char[N+1];
        memset(vis,0,sizeof(char)*(N+1));
        dp[0] = new int*[N+1];
        //从父节点出发要返回父节点走i步能吃到的最多苹果
        dp[1] = new int*[N+1];
        //从父节点出发不用返回父节点走i步能吃到的最多苹果
        if(K >= 2*(N-1))
            //超过最多的步数,可能未更新导致WA
        {
            K = 2*(N-1);
        }
        for(int i = 1;i <= N;i++)
        {
            dp[0][i] = new int[K+2];
            dp[1][i] = new int[K+2];
            memset(dp[0][i],0XDF,sizeof(int)*(K+2));       //设置极小值,但是两极小值相加又不会溢出为正数
            memset(dp[1][i],0XDF,sizeof(int)*(K+2));
        }
        processIn();
        DFS(1);
        maxVal = max(dp[0][1][K],dp[1][1][K]);
        printf("%d\n",maxVal);
    }
    ~solve()
    {
        vector<vector<int> >().swap(sons);
        delete[] vis;
        delete[] dp[0];
        delete[] dp[1];
    }
    int processIn();
    int DFS(int fa);
};

int solve::DFS(int fa)
{
    vis[fa] = 1;
    int sonSize = sons[fa].size();
    for(int i = 0;i < sonSize;i++)
    {
        int son = sons[fa][i];
        if(vis[son])
            //不能访问父节点及祖先节点
            continue;
        DFS(son);
        for(int j = K-1;j >= 0;j--)
            //倒序,使用上个子节点的数据
        {
            for(int k = 0;k <= j;k++)
            {
                dp[0][fa][j+2] = max(dp[0][fa][k]+dp[0][son][j-k],dp[0][fa][j+2]);
                //要返回fa,从son出发也必须返回son
                dp[1][fa][j+2] = max(dp[1][fa][k]+dp[0][son][j-k],dp[1][fa][j+2]);
                //不返回fa,fa->son->son->fa->others son
                dp[1][fa][j+1] = max(dp[0][fa][k]+dp[1][son][j-k],dp[1][fa][j+1]);
                //不返回fa,fa->others son->others son->fa->son
            }
        }
    }
    return 0;
}

int solve::processIn()
{
    for(int i = 1;i <= N;i++)
    {
        scanf("%d",dp[0][i]);
        dp[1][i][1] = dp[0][i][2] = dp[1][i][0] = dp[0][i][0];  //初始节点的最少收益
    }
    int fa,son;
    for(int i = 1;i < N;i++)
    {
        scanf("%d%d",&fa,&son);
        sons[fa].push_back(son);
        sons[son].push_back(fa);
    }
    return 0;
}

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        solve poj_2486(n,k);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值