DP知识点总结5 树形DP(实时更新)
一、树的直径
树的直径有两种求法,分别是两次dfs和树形dp,而 Acwing350巡逻 恰好都用到了这两种方法,详见个人的csdn博客
https://blog.csdn.net/zhangzhang232/article/details/116202867
二、树上状态划分
树上DP其实就是将一维线性DP的第一维用子树的根结点表示,所以如f[i][2]这样的线性DP,到树上就变成了树上状态划分的DP,经典例题有:
1.战略游戏
https://www.acwing.com/problem/content/description/325/
2.没有上司的舞会
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 using namespace std; 8 const int maxn=6666; 9 int n,m; 10 int r[maxn]; 11 int pd[maxn]; //用于判断上司 12 //int f[maxn]; //记忆化数组,以某点开始的最大快乐指数 13 14 int f[maxn][2];//不取和取当前点的情况 15 int root; 16 struct edge{ 17 int to,next; 18 edge(int u,int v):to(u),next(v){} 19 edge():to(0),next(0){} 20 }; 21 edge edges[maxn<<2]; 22 int h[maxn]; 23 int cnt; 24 void addedge(int from,int to){ 25 edges[++cnt].to=to; 26 edges[cnt].next=h[from]; 27 h[from]=cnt; 28 } 29 void dfs(int p){ 30 for(int i=h[p];i;i=edges[i].next){ 31 int too=edges[i].to; 32 dfs(too); 33 f[p][0]+=max(f[too][0],f[too][1]); 34 //f[p][1]+=max(f[too][0],f[too][1]); 35 f[p][1]+=f[too][0]; 36 } 37 f[p][1]+=r[p]; 38 } 39 int main(){ 40 41 // freopen("in.txt","r",stdin); 42 // freopen("out.txt","w",stdout); 43 44 scanf("%d",&n); 45 memset(f,0,sizeof(f)); 46 for(int i=1;i<=n;i++) scanf("%d",&r[i]); 47 int u,v; 48 while(scanf("%d%d",&u,&v)==2 && u && v){ 49 addedge(v,u); //先存边 50 pd[u]=1; 51 } 52 for(int i=1;i<=n;i++) if(pd[i]==0) root=i; //找树根 53 dfs(root); 54 //dfs(root,0,1); //取第一个点和不取第一个点 55 //cout<<f[root]; 56 printf("%d",max(f[root][0],f[root][1])); 57 //cout<<root; 58 return 0; 59 60 61 }
3.皇宫看守
https://www.acwing.com/problem/content/1079/
三、有依赖的背包问题
1.有依赖的背包问题
https://www.acwing.com/problem/content/10/
2.选课(以点为权重)
https://www.acwing.com/problem/content/288/
3.二叉苹果树(以边为权重)
https://www.acwing.com/problem/content/description/1076/
四、树上统计
对于树上的统计问题,统计子树的情况相对比较简单,因为只需要向下搜索即可。比较麻烦的类型是统计树上的一条路径,因为路径就需要向上找。
1.树的中心
https://www.acwing.com/problem/content/1075/
这道题的关键在于有一个向上统计的情况,其实向上统计仍然是向下统计。更新往上走的路径的时候,遍历方式仍然是从上往下,但是通过更新j而不是更新u实现了这个逆向的功能
五、二次扫描换根法
1.医院设置
https://www.luogu.com.cn/problem/P1364
自己推式子,移项后就能得到结果。首先从树根出发进行一次dfs统计,统计出一个数组,然后其它的点就能用dp的方式填f数组。
2.积蓄程度
https://www.acwing.com/problem/content/289/

浙公网安备 33010602011771号