还是很想引用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)