路径相关树形DP
学习内容
树上路径1
例题分析
先以树形DP的形式求出以某一个点为根的时候的答案(一般都是以1为根的时候),然后再进行一次自上而下的DFS计算答案。
也就是说,分两步,1.树形DP2.在进行第二次DFS时,两个点之间的关系。
首先,
如果我们假设某个节点为根,将无根树化为有根树,在搜索回溯时统计子树的深度和,则可以用一次搜索算出以该节点为根时的深度和,其时间复杂度为O(n)。如果我们每个点都这么求,则n^2
状态变化
这里的ans[u]表示以u为根节点的路径权重和,siz[v]表示以v为根节点的子树的节点个数:
ans[u]= ans[u]- siz[v]+(siz[1]- siz[v])
代码复现
from collections import defaultdict
def dfs(u, dep, fa): # 传入当前节点u,深度,父节点
global sum_depth
sum_depth += dep # 加上当前节点u的深度
# 遍历u的所有子节点
for v in e[u]:
if v == fa:
continue
dfs(v, dep + 1, u) # 遍历到子节点
siz[u] += siz[v] # 通过这一步,可以统计u所有子节点数
def dfs2(u, fa): # 用来跟新其余节点为根的解
for v in e[u]:
if v == fa:
continue
# dp[v] = dp[u] - siz[v] + (n - siz[v])
dp[v] = dp[u] - 2 * siz[v] + n # 当前节点v的解=左边变化值+右边变化值
dfs2(v, u)
n = int(input())
dp = [0] * (n + 1) # 用来更新不同节点为根时的深度和
siz = [1] * (n + 1) # 以i为根节点,其左子树的节点数,初始值为1表示仅包含该节点
# 建树
e = defaultdict(list)
for _ in range(n - 1):
u, v = map(int, input().split())
e[u].append(v)
e[v].append(u)
# 第一遍dfs,找到以1为根节点的深度和
sum_depth = 0 # 用来记录深度和
dfs(1, 0, 0)
# 第二遍dfs,求出其余点作为根的答案
dp[1] = sum_depth # 6
dfs2(1, 0) # dp=[0, 6, 5, 9, 8, 8]
print(max(dp))
树上路径2
题目分析
状态分析
感悟
我们可以看出换根DP的套路:(重点是分析子树与原来的状态变化)
指定某个节点为根节点。
1,第一次搜索完成预处理(如子树大小等),同时得到该节点的解
2,第二次搜索进行换根的动态规划,由已知解的节点推出相连节点的解。
蓝桥杯云课学习笔记分享,欢迎大佬们批评指正!
一直在进步就好咯!
by 闻不多