poj2342 Anniversary party(树形dp入门题)

http://poj.org/problem?id=2342

题目给你一个n表示总人数,然后又给了n个人的欢乐度,还有n-1个上下级关系。然后要求在n个人里选一些人,并且选的人里任意两人没有直接上下级的关系,问你最多可以选到的欢乐度是多少?

 题解:先定义状态dp[i][0]表示第i个人不去,子树i的最大欢乐度,dp[i][1]表示第i个人去,子树i的最大值。dp[i][1]先初始化为i节点的欢乐度,dp[i][0]初始化为0,随便选取一个点为根节点建一颗树,用dfs从上往下搜索,直到搜到了叶子节点,假设叶子节点j,因为叶子节点是没有儿子节点的,所以dp[j][0]=0,dp[j][1]=a[j],然后从叶子节点回溯到其父节点,对父节点(假设父节点i)的信息更新用,dp[i][0]+=max(dp[j][0],dp[j][1]),dp[i][1]+=dp[j][0],(这里之所以用+=是因为i节点的儿子节点可能不止一个),,就一直这样从下往上递推,最后max(dp[root][1],dp[root][0])就是要的答案.

#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
#include<string.h>
using namespace std;
#define maxn 6005
vector<int>son[maxn];//相当于邻接表,用来存边关系
bool vis[maxn];//标记访问过的节点
int dp[maxn][2];
void dfs(int root)//搜到叶子节点,然后回溯更新父节点的值
{
    vis[root]=1;
    for(int i=0;i<son[root].size();i++)
    {
        int v=son[root][i];
        if(!vis[v])
        {
            dfs(v);
            dp[root][1]+=dp[v][0];
            dp[root][0]+=max(dp[v][0],dp[v][1]);

        }
    }
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        son[i].clear();
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
            scanf("%d",&dp[i][1]);
            dp[i][0]=0;
    }
    int fa,so;
    while(scanf("%d%d",&so,&fa)!=EOF)
    {
        if(so==0&&fa==0) break;
        son[fa].push_back(so);
        son[so].push_back(fa);
    }
    dfs(1);//这里根节点是随便选取的
    cout<<max(dp[1][0],dp[1][1]);

}
原文地址:https://www.cnblogs.com/eason9906/p/11755090.html