某大学有 n n n 个职员,编号为 1 … n 1\ldots n 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r i r_i ri ,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入的第一行是一个整数 n n n。
第 2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行一个整数,第 ( i + 1 ) (i+1) (i+1)行的整数表示 i i i 号职员的快乐指数$ r_i$ 。
第$ (n + 2)$到第 2 n 2n 2n 行,每行输入一对整数 l , k l, k l,k,代表 k k k 是 l l l 的直接上司。
输出一行一个整数代表最大的快乐指数。
数据规模与约定 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 6 × 1 0 3 1\leq n \leq 6 \times 10^3 1≤n≤6×103, − 128 ≤ r i ≤ 127 -128 \leq r_i\leq 127 −128≤ri≤127, 1 ≤ l , k ≤ n 1 \leq l, k \leq n 1≤l,k≤n,且给出的关系一定是一棵树。
我们设 d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示 i i i要来的情况下以 i i i为根节点的子树的最大快乐值 d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示 i i i不来的情况下以 i i i为根节点的子树的最大快乐值
若 i i i要来,那么他的每一个子节点都只能不来, d p [ i ] [ 1 ] = ∑ d p [ j ] [ 0 ] , j 为 i 的 子 节 点 dp[i][1]=\sum dp[j][0],j为i的子节点 dp[i][1]=∑dp[j][0],j为i的子节点
如果ta不来,那么他的每个子节点就可来可不来, d p [ i ] [ 0 ] = ∑ m a x ( d p [ j ] [ 0 ] , d p [ j ] [ 1 ] ) , j 为 i 的 子 节 点 dp[i][0]=\sum max(dp[j][0],dp[j][1]),j为i的子节点 dp[i][0]=∑max(dp[j][0],dp[j][1]),j为i的子节点
我们需要从每个叶子节点向上不断跟新dp,直到求到根节点,这一步我们可以用递归的方式,对于每一个节点,先递归他的每一个子节点,再在回溯时执行更新操作
最终的答案就是看根节点是去还是不去, m a x ( d p [ r o o t ] [ 1 ] , d p [ r o o t ] [ 0 ] ) max(dp[root][1],dp[root][0]) max(dp[root][1],dp[root][0])’
Code:
#include<cstdio> #include<iostream> #include<vector> using namespace std; const int MAXN=6005; int h[MAXN]; vector<int> son[MAXN]; bool flag[MAXN]; int dp[MAXN][5]; int Max(int a,int b){ return a<b?b:a; } int Min(int a,int b){ return a<b?a:b; } void dfs(int x){ dp[x][0]=0; dp[x][1]=h[x]; for(int i=0;i<son[x].size();i++){ int y=son[x][i]; dfs(y); dp[x][0]+=Max(dp[y][0],dp[y][1]); dp[x][1]+=dp[y][0]; } } int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&h[i]); } for(int i=1;i<=n-1;i++){ int l,k; scanf("%d %d",&l,&k); son[k].push_back(l); flag[l]=1; } int root; for(int i=1;i<=n;i++){ if(!flag[i]){ root=i; break; } } dfs(root); printf("%d",Max(dp[root][1],dp[root][0])); return 0; }