树形dp练习
洛谷P1352 没有上司的舞会
经典的树形dp
设
f[x][0]表示以x为根的子树,且x不参加舞会的最大快乐值
f[x][1]表示以x为根的子树,且x参加了舞会的最大快乐值
则f[x][0]=sigma{max(f[y][0],f[y][1])} (y是x的儿子)
f[x][1]=sigma{f[y][0]}+h[x] (y是x的儿子)
先找到唯一的树根root
则ans = max(f[root][0], f[root][1])
#include <bits/stdc++.h> using namespace std; const int maxn = 6e3 + 7; struct edge { int to, next; }e[maxn]; int r[maxn], head[maxn], cnt, f[maxn][2]; bool mark[maxn], vis[maxn]; void add(int u, int v) { e[++cnt].next = head[u]; e[cnt].to = v; head[u] = cnt; } void dfs(int x) { vis[x] = 1; if(!head[x]) //x为叶子结点 { f[x][0] = 0; f[x][1] = r[x]; //所以可以简化为无需r数组,开始直接读入f[x][1],这样最后也不用+=r[x]了 return; } for(int i = head[x]; i; i = e[i].next) //遍历以x为起点的所有边 { int y = e[i].to; if(vis[y]) continue; dfs(y); //在下两行使用y前,保证y已经计算出来 f[x][0] += max(f[y][0], f[y][1]); f[x][1] += f[y][0]; } f[x][1] += r[x]; return; } int main() { int n, a, b; cin >> n; for(int i = 1; i <= n; ++i) scanf("%d", &r[i]); for(int i = 1; i <= n - 1; ++i) { scanf("%d %d", &a, &b); add(b, a); //加边是单向的,a是b的父亲,b不是a的父亲 mark[a] = 1; } for(int i = 1; i <= n; ++i) { if(!mark[i]) //找到根 { dfs(i); printf("%d\n", max(f[i][0], f[i][1])); return 0; } } }