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
",nback[1][m]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wangfang20/p/3252450.html