Description
Input
Output
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
先废话两句:
已经一个月没写题解了真是太过分了……坚决不能再这样了!!!!!!!!!!!
这是一道经典的树形dp,有现成的翻译哈哈:
没有上司的舞会
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
输入格式
第一行一个整数N。(1<=N<=6000)接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。最后一行输入0,0。
输出格式
输出最大的快乐指数。
刚刚看到这个题的时候还是有点迷茫的,不过想起高中老师说过:树形dp实际上就是在找出转移方程以后后序遍历一次,于是……
f[x][1]表示x要去时能获得的最大的快乐指数
f[x][0]表示x不去时能获得的最大的快乐指数那么假设k1,k2……ki是x的下属:f[x][1] =a[x] + f[k1][0] + f[k2][0]+……+ f[ki][0] //X要去,那他的下属们都不能去f[x][0] =max(f[k1][0],f[k1][1]) +max(f[k2][0],f[k2][1])+……+ max(f[ki][0],f[ki][1])//X不去,那他的下属们可去可不去(取最大)然后写个后序遍历,然后在返回的时候进行转移就解决问题了#include <iostream> #include <cstdio> #include <cstring> using namespace std; const long N = 6010; long n, root; long a[N], fa[N]; bool v[N]; long f[N][2]; void init() { memset(f, 0, sizeof(f)); for (long i=1; i<=n; i++) { scanf("%d", &a[i]); f[i][1] = a[i]; } long l, k; memset(fa, 0, sizeof(fa)); while ((scanf("%d%d", &l, &k) != EOF) && (l > 0) && (k > 0)) { fa[l] = k; } for (long i=1; i<=n; i++) { if (fa[i] == 0) root = i; } memset(v, 0, sizeof(v)); } void dfs(long x) { v[x] = 1; for (long i=1; i<=n; i++) { //printf("%d %d %d %d\n", x, i, v[i], fa[i]); if ((!v[i]) && (fa[i] == x)) { dfs(i); f[x][0] += max(f[i][1], f[i][0]); f[x][1] += f[i][0]; } } } int main() { while(scanf("%d", &n) != EOF) { init(); dfs(root); // printf("%d\n", root); printf("%d\n", max(f[root][0], f[root][1])); } return 0 ; }