洛谷 P1352 没有上司的舞会 树形DP
【题目描述】
某大学有 n 个职员,编号为 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 ri ,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
【输入格式】
输入的第一行是一个整数 n。
第 2 到第 (n+1) 行,每行一个整数,第 (i+1) 行的整数表示 i 号职员的快乐指数 ri。
第 (n+2) 到第 2n 行,每行输入一对整数 l,k,代表 k 是 l 的直接上司。
【输出格式】
输出一行一个整数代表最大的快乐指数。
【输入输出样例】
输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出
5
【解题思路】
树形DP的模板题。
首先找到最高上司,依次考虑每个人来或不来(结点的dp[0]或[1])的情况,递归调用treedp函数即可。
【AC代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=6005;
int n,a,b,fat[maxn],vis[maxn],dp[maxn][2];
void treedp(int node)
{
vis[node]=1;
for(int i=1;i<=n;i++)
{
if(vis[i]==0&&fat[i]==node)
{
treedp(i);
dp[node][0]+=max(dp[i][0],dp[i][1]);
dp[node][1]+=dp[i][0];
}//0表示不来,1表示来
}
}//树形DP
int main()
{
scanf("%d",&n);
memset(fat,0,sizeof(fat));
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
int root=1;
for(int i=1;i<=n;i++)
scanf("%d",&dp[i][1]);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&a,&b);
fat[a]=b;
//if(root==a) root=b;
}
while(fat[root])
root=fat[root];//找到最高上司
treedp(root);
printf("%d\n",max(dp[root][0],dp[root][1]));
return 0;
}