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/

posted @ 2021-04-30 18:27  _rhinoceros  阅读(167)  评论(0)    收藏  举报