树形dp

谁说胖子不能爱 提交于 2019-12-04 02:34:51

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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!