舞会
Description
Arthur公司是一个等级森严的公司,它们有着严格的上司与下属的关系,公司以总裁为最高职位,他有若干个下属,他的下属又有若干个下属,他的下属的下属又有若干个下属……现接近年尾,公司组织团拜活动,活动中有一部分是自由舞会,公司的每个职员都有一个搞笑值,现要你制定一套哪些人上台的方案,使得台上所有演员的搞笑值最大。当然,职员们是不会和他们的顶头上司一起上台
Input
第一行一个整数N,表示这个公司总共的职员个数。
接下来一行有N个整数,由空格隔开,第i个整数表示职员i的搞笑值Ai(-1327670≤Ai≤1327670)。
接下来N-1行,每行一个1到N的整数,第i个整数表示职员i+1的顶头上司是谁,当然总裁就是职员1。
Output
一个整数,表示台上所有职员搞笑值之和的最大值。
Sample Input
7 1 1 1 1 1 1 1 1 1 5 1 4 4
Sample Output
5
Answer
/**
这是一个树形DP
设dp[i][0]为在下标为i的节点的子树上得到的最大值(不取根节点i)
设dp[i][1]为在下标为i的节点的子树上得到的最大值(取根节点i)
那么dp[i][0] += max(dp[q][0],dp[q][1]); ==>q∈{i点的子节点}
而dp[i][1] += dp[q][0]; ==>q∈{i点的子节点}
记忆化搜索即可
**/
#include
#define maxn (5000 + 10)
using namespace std;
int dp[maxn][2];
vector
Vec[maxn];
int va[maxn];
int n;
void DFS(int p) {
// printf("%d \n",p);
if(p > n) return;
if(dp[p][0] != -1 || dp[p][1] != -1) return;
if(Vec[p].size() == 0) {
dp[p][1] = va[p];
dp[p][0] = 0;
return ;
}
for(int i = 0; i < Vec[p].size(); i ++) DFS(Vec[p][i]);
dp[p][0] = 0;
dp[p][1] = va[p];
for(int i = 0; i < Vec[p].size(); i ++) {
int q = Vec[p][i];
dp[p][0] += max(dp[q][0],dp[q][1]);
dp[p][1] += dp[q][0];
}
}
int main() {
// freopen("in.txt","r",stdin);
memset(dp,-1,sizeof(dp));
scanf("%d",&n);
for(int i = 1; i <= n; i ++) {
scanf("%d",&va[i]);
}
for(int i = 1; i <= n; i ++) {
if(i == 1) continue;
int pre;
scanf("%d",&pre);
Vec[pre].push_back(i);
}
DFS(1);
printf("%d\n",max(dp[1][0],dp[1][1]));
return 0;
}