poj 2486 树形dp

思路:这题是裸的树形dp。dp[i][j]表示第i个节点花费j步并且从子节点返回,能得到的最大苹果数;nback[i[j]表示第i个节点花费j步并且进入某个子节点不返回,能得到的最大苹果数。那么我们就能得到动态方程:

根节点为u,子节点为v

dp[u][j]=max(dp[u][j],dp[u][j-k-2]+dp[v][k]);
nback[u][j]=Max(nback[u][j],nback[u][j-k-2]+dp[v][k],dp[u][j-k-1]+nback[v][k]);//表示对某个节点可以选择进入返回或不返回.

#include<iostream>

#include<algorithm>

#include<cstring>

#include<cstdio>

#include<vector>

#define Maxn 210

using namespace std;

int vi[Maxn],val[Maxn],dp[Maxn][Maxn],n,m,nback[Maxn][Maxn];

vector<int> head[Maxn];

void init()

{

    memset(vi,0,sizeof(vi));

    memset(val,0,sizeof(val));

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

    memset(nback,0,sizeof(nback));

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

        head[i].clear();

}

inline int Max(int a,int b,int c)

{

    int temp=a>b?a:b;

    return temp>c?temp:c;

}

void add(int u,int v)

{

    head[u].push_back(v);

    head[v].push_back(u);

}

void dfs(int u)

{

    int i,v,sz,j,k;

    vi[u]=1;

    sz=head[u].size();

    int s1,s2;

    s1=s2=0;

    for(i=0;i<sz;i++)

    {

        v=head[u][i];

        if(vi[v]) continue;

        dfs(v);

        for(j=m;j>=1;j--){

                s1=s2=0;

            for(k=0;k<=j-1;k++){

                if(j-k>=2)

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

                s2=Max(s2,nback[u][j-k-2]+dp[v][k],dp[u][j-k-1]+nback[v][k]);

            }

            dp[u][j]=max(dp[u][j],s1);

            nback[u][j]=max(nback[u][j],s2);

        }

    }

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

        dp[u][i]+=val[u];

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

        nback[u][i]+=val[u];

}

int main()

{

    int i,j,a,b;

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

    {

        init();

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

            scanf("%d",val+i);

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

            scanf("%d%d",&a,&b);

            add(a,b);

        }

        dfs(1);

        printf("%d\n",nback[1][m]);

    }

    return 0;

}

 

你可能感兴趣的:(poj)