ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树上问题

2021-08-03 07:34:14  阅读:144  来源: 互联网

标签:复杂度 dfs 节点 问题 树上 转移 DP size


树形DP:

  DP巧妙之处在于状态设计,即将多个类似信息放在一起

考虑,这也是DP的最优子结构性质,而树形DP常以记录根

节点信息进行转移,因为通常以根节点子树为DP阶段,而仅

有根节点信息会阶段外信息造成影响。

  例1:选课

  传统树形背包,利用树的递归性质,即子树(子集合)

之间的独立性分而治之,时间复杂度O(nm^2)考虑时间复杂

度瓶颈。

  方案一:序列上的背包DP时间复杂度O(nm),原因在于

每次合并一种物品,更新答案。树上合并复杂度瓶颈在于n

次合并,每次合并一颗子树的信息,故每次合并都要枚举子

树信息与背包容量,时间复杂度O(nm^2)。

  于是考虑降低时间复杂度,根据之前的分析也就是考虑

如何每次只合并一个信息(避免枚举大量信息),于是联想

序列背包的模式,考虑将树上合并转化为序列合并,显然只

需要求出树的dfs序即可,转移时要遵循由子节点转移到父节

点因此向前枚举,注意由于本质上仍然为树形DP,故当不选

当前节点时,上一个状态为f[i+size[aux[i]]]代表如果不选当前

节点则整个子树都无法选择。

  思想:时间复杂度瓶颈分析与优化,树的性质,树上问题

转化为序列问题

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define V void
 5 const I N = 5e3 + 3;
 6 I n,m,tot,cnt,head[N],to[N],nxt[N],cre[N],aux[N],f[N][N],size[N];
 7 inline V found (I x,I y) {
 8     to[++tot] = y,nxt[tot] = head[x],head[x] = tot;
 9 }
10 V dfs (I x) {
11     size[x] = 1,aux[cnt++] = x;
12     for (I i(head[x]); i ;i = nxt[i])
13       dfs (to[i]),size[x] += size[to[i]];
14 }
15 signed main () {
16     scanf ("%d%d",&n,&m);
17     for (I i(1),x;i <= n; ++ i) scanf ("%d%d",&x,&cre[i]),found (x,i);
18     dfs (0);
19     for (I i(n); i ; -- i)
20       for (I j(m); j ; -- j)
21         f[i][j] = max (f[i + 1][j - 1] + cre[aux[i]],f[i + size[aux[i]]][j]);
22     printf ("%d\n",f[1][m]);
23 }
View Code

   方案二:较劣的时间复杂度意味着存在冗余转移,于是

考虑优化状态数,发现对于序列问题每个元素由1~m的容量

完成转移,而当转移子树时由1~m^2容量遍历完成转移,而

实际节点数并没有那么多,于是考虑优化转移数。

  观察转移方程发现冗余转移在于m^2枚举,于是考虑对于

当前需要转移的子树进行上下界压缩,压缩为其合理转移数,

对于当前子树待转移量为子树大小,而当前树待转移量为已经

合并的子树大小,于是在递归过程中记录两个信息进行状态数

压缩即可,时间复杂度O(nm)考虑转移量即可

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 const I N = 5e3 + 3;
 5 I f[N][N],s[N],n,m;
 6 vector<I> e[N];
 7 I dfs(I u) {
 8     I p = 1;
 9     f[u][1] = s[u];
10     for (auto v : e[u]) {
11       I siz = dfs(v);
12       for (I i = min(p, m + 1); i; i--)
13         for (I j = 1; j <= siz && i + j <= m + 1; j++)
14           f[u][i + j] = max(f[u][i + j], f[u][i] + f[v][j]);
15       p += siz;
16     }
17     return p;
18 }
19 I main() {
20     scanf("%d%d", &n, &m);
21     for (I i = 1,x; i <= n; i++) scanf("%d%d", &x, &s[i]),e[x].push_back(i);
22     dfs(0);
23     printf("%d\n",f[0][m + 1]);
24 }
View Code

思想:压缩状态数优化时间复杂度,考虑上下界问题

标签:复杂度,dfs,节点,问题,树上,转移,DP,size
来源: https://www.cnblogs.com/HZOI-LYM/p/15090958.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有