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

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

树上的动态编程套装1

树上的动态编程套装1是一组算法技巧和数据结构,用于解决树形结构上的动态规划问题。它可以高效地处理如树的最长路径、树的直径、树的重心等问题。

算法介绍
树形DP

树形DP是指在树上进行动态规划的一类算法。树形DP常常需要找到合适的状态表示方法和状态转移方程。通常采用自底向上的递归方式进行状态转移,最终得到根节点上的最优解。

树的重心

树的重心是指在一棵树上,能够最小化最大子树大小的节点。树的重心可以用dfs递归求解,时间复杂度为$O(n)$。

def dfs(u, fa):
    size[u] = 1
    max_child_size = 0
    for v in g[u]:
        if v == fa:
            continue
        dfs(v, u)
        size[u] += size[v]
        max_child_size = max(max_child_size, size[v])
    max_child_size = max(max_child_size, n - size[u])
    if max_child_size < min_size:
        min_size = max_child_size
        centroid = u
树的直径

树的直径是指树上距离最远的两个节点之间的距离。树的直径可以用两次dfs求解,时间复杂度为$O(n)$。

def dfs(u, fa):
    dist[u] = 0
    for v in g[u]:
        if v == fa:
            continue
        dfs(v, u)
        dist[u] = max(dist[u], dist[v] + 1)

def find_diameter():
    dfs(1, 0)
    u = dist.index(max(dist))
    dfs(u, 0)
    v = dist.index(max(dist))
    return (u, v, dist[v])
树的最长路径

树的最长路径指树上两个节点之间的最长路径。树的最长路径可以用两次dfs和树的直径求解,时间复杂度为$O(n)$。

def dfs(u, fa):
    dist[u] = 0
    for v in g[u]:
        if v == fa:
            continue
        dfs(v, u)
        d = dist[v] + 1
        if d > dist[u]:
            dist2[u] = dist[u]
            dist[u] = d
            son[u] = v
        elif d > dist2[u]:
            dist2[u] = d

def find_longest_path():
    _, u, _ = find_diameter()
    dfs(u, 0)
    res = dist[u]
    for v in g[u]:
        if v == son[u]:
            res = max(res, dist2[u] + 1)
        else:
            res = max(res, dist[u] + 1)
    return res
总结

树上的动态编程套装1可以用于高效处理树的一些关键问题,如树的重心、树的直径和树的最长路径等。它基于树形DP和dfs的算法技巧,需要找到合适的状态表示和状态转移方程。