📌  相关文章
📜  从距离节点X最多D个距离节点的子树中查找最小权重的查询(1)

📅  最后修改于: 2023-12-03 14:49:28.557000             🧑  作者: Mango

从距离节点X最多D个距离节点的子树中查找最小权重的查询

在一棵树中,给定一个节点X和一个整数D,任务是找到从节点X到最多D个距离节点的子树中的最小权重值。这项任务可以通过深度优先搜索和动态规划技术来完成,时间复杂度为O(n)。

算法思路

为了完成此任务,我们首先需要建立一棵树,并使用动态规划技术计算每个节点的权重。对于每个节点,我们可以计算其子树中的最小权重值,并将其存储在该节点上。使用这些数据,我们可以轻松地找到从节点X到距离最多D个节点的最小权重值。

具体做法如下:

  1. 对于每个节点i,计算其权重wi,也就是子树中包含i的子树的最小权重值。因此,所有叶子节点的权重值均为其本身。

  2. 对于内部节点i,将其子节点的权重值按照从小到大的顺序排序,即w1<=w2<=...<=wk,其中k为i的子节点数。计算i的权重值wi为w1+2w2+...+kwk。

  3. 对于每个节点i,计算其最小子树权重值minwi。这可以通过递归地计算每个子节点的权重值得到:minwi=min{minwj+wi−wj},其中wj为i的一个子节点。

  4. 对于每个节点i,计算其距离节点X不超过D,且权重值最小的节点j。这可以通过递归地计算每个子节点的最小子树权重值得到:min{minwv+minwu+2(wi−wv−wu)},其中v和u为i的两个子节点,wv<=wu,距离节点X的最短距离为max{dist(v,X),dist(u,X)+1}。

代码实现

以下是使用Python实现上述算法的代码片段:

class Node:
    def __init__(self, val):
        self.val = val
        self.children = []
        self.weight = 0
        self.min_weight_subtree = float('inf')

def build_tree():
    nodes = []
    for i in range(n):
        nodes.append(Node(weights[i]))

    for i in range(n - 1):
        u, v = map(int, input().split())
        nodes[u - 1].children.append(nodes[v - 1])

    return nodes[x - 1]

def calc_weight(node):
    if node.children:
        node.children.sort(key=lambda x: x.weight)
        for i, child in enumerate(node.children):
            child.weight = node.weight + (i + 1) * child.weight
            calc_weight(child)
        node.weight = sum(child.weight for child in node.children)

def calc_min_weight_subtree(node):
    if not node.children:
        node.min_weight_subtree = node.weight
    else:
        for child in node.children:
            calc_min_weight_subtree(child)
        for i in range(len(node.children)):
            for j in range(i + 1, len(node.children)):
                v, u = node.children[i], node.children[j]
                min_weight = v.min_weight_subtree + u.min_weight_subtree + 2 * (node.weight - v.weight - u.weight)
                node.min_weight_subtree = min(node.min_weight_subtree, min_weight)

def find_min_weight(root, d):
    if d == 0:
        return root.weight
    min_weight = root.min_weight_subtree
    for child in root.children:
        if d - 1 >= max(find_path_len(child, x) for x in leafs) - 1:
            min_weight = min(min_weight, find_min_weight(child, d - 1))
    return min_weight

n, x, d = map(int, input().split())
weights = list(map(int, input().split()))
root = build_tree()
calc_weight(root)
calc_min_weight_subtree(root)
leafs = [node for node in root.children if not node.children]
print(find_min_weight(root, d))

其中,输入格式为:

  • 第1行包含3个整数n、x和d,分别表示树的节点数、起点节点和最大距离。
  • 第2行包含n个整数,表示每个节点的权重值。
  • 接下来n-1行,每行包含2个整数u和v,表示节点u和v之间存在一条边。
  • 输出为从节点x到距离最多d个节点的子树中的最小权重值。

代码中使用Node类来表示树的节点,包含节点值、子节点列表、权重值和最小子树权重值等属性。build_tree函数构建树节点,并根据输入的边信息将它们连接起来。calc_weight函数计算每个节点的权重值,calc_min_weight_subtree函数计算每个节点的最小子树权重值,find_min_weight函数根据距离约束,查找从节点X到最多D个距离节点的子树中的最小权重值。