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]);
}