树形dp就是在树的结构上用动态规划,主要用DFS。
1
| dp[i][j][0/1],其中i指以i为根的子树,j指在以i为根的子树中选择j个子节点,0表示不选这个节点,1表示选择这个节点。有时候j或0/1这一维可以压掉。
|
基本方程:
选择节点类
1 2
| dp = dp dp = max/min(dp, dp)
|
树形背包类
1 2
| dp = dp + val dp = max(dp, dp)
|
入门题1:没有上司的舞会
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <iostream> #include <vector> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int maxn = 6005; int n, root, r[maxn], f[maxn][2], v[maxn]; vector<int>s[maxn]; void dp(int x){ f[x][0] = 0; f[x][1] = r[x]; for(int i = 0; i < s[x].size(); i++){ int t = s[x][i]; dp(t); f[x][0] += max(f[t][0], f[t][1]); f[x][1] += f[t][0]; } } int main(){ cin >> n; for(int i = 1; i <= n; i++) cin >> r[i]; int l, k; memset(v, 0, sizeof(v)); for(int i = 1; i <= n-1; i++){ cin >> l >> k; s[k].push_back(l); v[l] = 1; } for(int i = 1; i <= n; i++) if(!v[i]){ root = i; break; } dp(root); cout << max(f[root][0], f[root][1]) << endl; return 0; }
|
参考资料