又是一道树形DP,做了两道树型DP,现在来总结一下.
在这两题中,有一个共同点,就是为任何一个子树设置一组状态变量。在本题中,设置状态变量A、B,然后导出了状态变量转换方程,再使用DFS对状态变量逐次求解,就做出了这道题。
总的来说,本题还是比较简单的。
/*
1380 没有上司的舞会
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
输入描述 Input Description
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。
输出描述 Output Description
输出最大的快乐指数。
样例输入 Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
样例输出 Sample Output
5
思路
设置任何一个节点拥有两个属性:
A:如果包括该节点,最大欢乐度
B:如果不包括该节点,最大欢乐度
那么答案则为
max(root.A,root.B);
然后对于任何一个节点R,认为他的所有儿子为C1、C2。。。。。。
可以得到
R.A = R.Num + C1.B + C2.B + .....
R.B = max(C1.A,C1.B) + max(C2.A,C2.B) + .......
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int child;
node* next;
node(int _child = 0, node* _next = NULL){//认为0为nil
child = _child;
next = _next;
}
};
node *list[7000];
int Num[7000];
int A[7000];
int B[7000];
void DFS(int now, int N){
int i, j;
node* tmp;
for (tmp = list[now]; tmp != NULL; tmp = tmp->next){
DFS(tmp->child, N);
A[now] += B[tmp->child];
B[now] += max(A[tmp->child], B[tmp->child]);
}
}
int solve(const int N,int root){
int i, j, k;
for (i = 1; i <= N; i++)A[i] = Num[i];
memset(B, 0, sizeof(B));
DFS(root, N);
return max(A[root], B[root]);
}
int main(void){
int N, i, j;
while (cin >> N){
memset(Num, 0, sizeof(Num));
memset(list, 0, sizeof(list));
for (i = 1; i <= N; i++){
scanf("%d", Num + i);
}
int a, b,root = 1;
scanf("%d %d", &a, &b);
while (a != 0 && b != 0){
node *tmp = new node(a, list[b]);
list[b] = tmp;
if (a == root)root = b;//寻找根节点
scanf("%d %d", &a, &b);
}
cout << solve(N,root) << endl;
for (i = 0; i < 7000; i++){
while (list[i] != NULL){
node* tmp = (list[i]);
list[i] = list[i]->next;
delete tmp;
};
}
}
return 0;
}