📜  树上的动态编程套装1(1)

📅  最后修改于: 2023-12-03 15:40:27.113000             🧑  作者: Mango

树上的动态编程套装1

本文主要介绍树上动态规划算法的套件,使用该套件可以解决一系列树上动态规划问题。

前置知识

在使用该套件之前,你需要掌握以下知识:

  • 动态规划算法基本思想
  • 树的基本概念和遍历方式
  • 树形DP的基本概念和实现方式
动态编程套件介绍

该套件包含以下算法:

  • 树的重心:找到树的重心
  • 树的直径:找到树的直径
  • 树的深度:求树中每个节点的深度
  • 树的直径路径:找到树的直径路径
  • LCA(最近公共祖先):找到两个节点的最近公共祖先
  • 树的节点独立集:找到树的最大独立集
树的重心

树的重心是指树中某个节点,如果把该节点和它的子树删除,剩余子树的节点数最大。

def get_centroid(u, p, sz, w):
    for v in w[u]:
        if v != p:
            get_centroid(v, u, sz, w)
            sz[u] += sz[v]
    mx = max(sz[v] for v in w[u] if v != p)
    if max(mx, len(w) - sz[u]) <= len(w) // 2:
        return u
树的直径

树的直径是指树中最长的路径。

def get_diameter(u, p, d, w):
    dia = [d[u], 0]
    for v in w[u]:
        if v != p:
            res = get_diameter(v, u, d + 1, w)
            dia = max(dia, res, key=lambda x: x + 1)
    return dia
树的深度

树的深度是指从根节点到每个节点的路径长度。

def get_depths(u, p, d, dp, w):
    dp[u] = d
    for v in w[u]:
        if v != p:
            get_depths(v, u, d + 1, dp, w)
树的直径路径

树的直径路径即为树的直径所连接的两个节点之间的路径。

def get_diameter_path(u, p, d, w):
    res = [(u, d)]
    for v in w[u]:
        if v != p:
            res = max(res, get_diameter_path(v, u, d + 1, w), key=lambda x: x[1])
    return res if p is not None else res[:-1]
LCA

LCA是指两个节点的最近公共祖先。

def get_lca(u, v, p, dp, w):
    while dp[u] > dp[v]:
        u, v = v, u
    while dp[u] < dp[v]:
        v = p[v]
    while u != v:
        u, v = p[u], p[v]
    return u
树的节点独立集

树的节点独立集是指树中最大独立节点集合。

def get_maximum_independent_set(u, p, dp, dp1, dp2, w):
    dp1[u] = 1
    dp2[u] = 0
    for v in w[u]:
        if v != p:
            get_maximum_independent_set(v, u, dp, dp2, dp1, w)
            dp1[u] += dp2[v]
            dp2[u] += max(dp1[v], dp2[v])
总结

树上动态规划是一类常见的问题,常常需要使用到一些套装算法,如本文中介绍的树的重心、树的直径、树的深度、树的直径路径、LCA和树的节点独立集算法,它们可以很好地应用于处理树上的问题。