树形dp模板题~ 题目在这里
题目大意:
Ural大学要举办一个庆典,每个职员都有一个欢乐值,但是没有一个职员想要和他们的直属上司一起出席(会很拘束哎),题目给出职员和他们的上司以及他们的欢乐值,求出这个宴会可能达到的最大的欢乐值是多少。
题目思路:
很显然职员之间不会有约束关系,那么我们可以发现这些约束关系其实是一棵树,根据题意,我们如果选择这个节点参加,那么他的儿子们就都不能参加,我们只能选择他的孙子;相反,如果这个节点不参加,那么他的儿子可以参加也可以不参加。
这样我们就可以设出数组dp[i][0]表示不选择i这个节点时可以达到的最大欢乐值,dp[i][1]表示选择这个节点时可以达到的最大欢乐值;那么,dp[root][0]=max(dp[son][0],dp[son][1]),dp[root][1]=dp[son][0];下面结合代码来说明:
另:建树最好用vector邻接表来实现,不但节省空间而且超好用!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 10000
using namespace std;
vector<int>son[maxn];
bool vis[maxn];
int dp[maxn][2];
int n;
void dfs(int root)//分别得到选root和不选root的最大欢乐值
{
vis[root]=true;
for(int i=0;i<son[root].size();i++)
{
int v=son[root][i];//root的儿子们
if(!vis[v])
{
dfs(v);
dp[root][1]+=dp[v][0];//注意是要加上的,因为他的子树能达到的其实包含在他能达到的
dp[root][0]+=max(dp[v][0],dp[v][1]);
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<=n;i++)
son[i].clear();
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++)
{
scanf("%d",&dp[i][1]);//初始化
dp[i][0]=0;
}
int l,k;
while(~scanf("%d%d",&l,&k)&&(l+k))//建树过程
{
son[l].push_back(k);
son[k].push_back(l);
}
dfs(1);
int ans=max(dp[1][0],dp[1][1]);
printf("%d\n",ans);
}
return 0;
}
呼呼