还是很想引用lyd《算法竞赛进阶指南》总的几句话。
在树上设计动态规划时,一般就以节点从深到浅(子树由大到小)的顺序作为dp的阶段。
在方程中一般第一维是节点编号,代表以该节点为根的子树。
大多数情况下都采用递归的形式实现树形dp。
对于每个节点x,先递归它的每个子节点进行dp,在回溯时,从子节点向节点x进行状态转移。
举个栗子:
一个n个节点的树,每个点有权值Vi,根节点与子节点不能同时取,求总权值的最大值。

1 #include<iostream>
2 #include<vector>
3 using namespace std;
4 int n,f[7000][3];
5 int vis[7000],h[7000];
6 vector<int>son[7000];
7 void dp(int x)
8 {
9 f[x][1]=h[x];
10 f[x][0]=0;
11 for(int i=0;i<son[x].size();i++)
12 {
13 int y=son[x][i];
14 dp(y);
15 f[x][0]+=max(f[y][1],f[y][0]);
16 f[x][1]+=f[y][0];
17 }
18 }
19 int main()
20 {
21 int x,y;
22 cin>>n;
23 for(int i=1;i<=n;i++)
24 cin>>h[i];
25 while(true)
26 {
27 cin>>x>>y;//y是x上司
28 if(x==0&&y==0)break;
29 vis[x]=1;
30 son[y].push_back(x);
31 }
32 int root;
33 for(int i=1;i<=n;i++)
34 {
35 if(!vis[i])
36 {
37 root=i;
38 break;
39 }
40 }
41 dp(root);
42 cout<<max(f[root][1],f[root][0]);
43 return 0;
44 }
来分析这个题的话,dp的第一维表示节点状态,可以用01分别代表不选和选。
f[x,1]表示以x为根的子树,并且x选所能产生的最大值。
f[x,0]表示以x为根的子树,并且x不选的最大值。
很显然的动态转移方程:
f[x,0]=max(f i)
