【题目描述】
Ural大学有N个职员,编号为1~N。 他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。 每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。 但是,没有职员愿和直接上司一起与会。
请你求出最大的快乐指数。
【题目链接】
CodeVS 1380 没有上司的舞会
【解题思路】
树形DP,设$f[v][0\ or\ 1]$表示节点$v$ 不参加/参加 舞会的情况下,该子树内的最大快乐指数。
转移是很好理解的。 如果他去,那么他的子节点都不去,对所有子节点不去时的最大快乐指数求和,再加上本身,即可。 如果他不去,那么对所有子节点的最大快乐指数求和即可。
$$ f[v][0] = \sum max(f[v.child][0], f[v.child][1]) $$ $$ f[v][1] = v.w + \sum f[v.child][0]$$
【AC代码】
并没有说0是根节点,QwQ。
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXN 6000
struct Node{
Node *child, *next;
int w;
bool isRoot;
int f[2];
Node(){
child = next = NULL;
isRoot = true;
f[0] = f[1] = 0;
}
void solve(){
for(Node *v = child; v; v = v->next){
v->solve();
f[0] += std::max(v->f[1], v->f[0]);
f[1] += v->f[0];
}
f[1] += w;
}
} vs[MAXN];
inline void addChild(int a, int b){
Node *u = vs + a, *v = vs + b;
v->next = u->child, u->child = v;
}
int main(){
int n;
scanf("%d", &n);
for(Node *v = vs; v != vs + n; v++) scanf("%d", &v->w);
for(int i = 0; i < n - 1; i++){
int u, v;
scanf("%d%d", &u, &v), u--, v--;
vs[u].isRoot = false;
addChild(v, u);
}
for(Node *v = vs; v != vs + n; v++){
if(v->isRoot){
v->solve();
printf("%d", std::max(v->f[1], v->f[0]));
break;
}
}
return 0;
}
就是这样啦。