POJ2486 - Apple Tree(树形DP)

题目大意

给定一棵n个结点的树,每个结点上有一定数量的苹果,你可以从结点1开始走k步(从某个结点走到相邻的结点算一步),经过的结点上的苹果都可以吃掉,问你最多能够吃到多少苹果?

题解

蛋疼的问题就是可以往回走~~~~想N就木有想到解法,看了下网上的解题报告~~~~想到了其实还是挺容易理解的~~~分为两种情况,就是有些点只需要走一次,而有些则需要走两次。

方程表示:

dp[0][u][j]表示从结点u开始走j步并且返回到结点u获得的最大价值

dp[1][u][j]表示从结点u开始走j步不回到结点u获得的最大值

dp[0][u][j]=max(dp[0][u][j],dp[0][u][j-k-2]+dp[0][v][k])(子节点v走完k步之后返回v,边(u,v)走了两次,所以其他子树需要走j-k-2步,并且也返回)

dp[1][u][j]=max(dp[1][u][j],dp[1][u][j-k-2]+dp[0][v][k])(子树v走完k步返回结点u,同样,边(u,v)走了两次,所以其他子树也需要走j-k-2步,不返回)

dp[1][u][j]=max(dp[1][u][j],dp[0][u][j-k-1]+dp[1][v][k])(先从结点u开始在除子树v外其他的子树走j-k-1步并且返回,边(u,v)只需要走一次,然后再在子树v走k步,不返回)

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <vector>

using namespace std;

#define MAXN 105

vector<int> G[MAXN];

int dp[2][MAXN][MAXN*2],value[MAXN];

int n,m;

void dfs(int u,int fa)

{

    for(int i=0;i<=m;i++) 

    {

        dp[0][u][i]=dp[1][u][i]=value[u];

    }

    for(size_t i=0;i<G[u].size();i++)

    {

        int v=G[u][i];

        if(fa==v) continue;

        dfs(v,u);

        for(int j=m-1;j>=0;j--)

        {

            for(int k=0;k<=j;k++)

            {

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

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

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

            }

        }

    }

}

int main()

{

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(int i=1;i<=n;i++) 

            scanf("%d",&value[i]);

        for(int i=0;i<MAXN;i++) G[i].clear();

            memset(dp,0,sizeof(dp));

        for(int i=1;i<n;i++)

        {

            int u,v;

            scanf("%d%d",&u,&v);

            G[u].push_back(v);

            G[v].push_back(u);

        }

        dfs(1,-1);

        printf("%d\n",max(dp[0][1][m],dp[1][1][m]));

    }

    return 0;

}

 

          

 

你可能感兴趣的:(apple)