Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 条件下树遍历和节点值求和的最优解_Algorithm_Optimization_Tree_Computer Science - Fatal编程技术网

Algorithm 条件下树遍历和节点值求和的最优解

Algorithm 条件下树遍历和节点值求和的最优解,algorithm,optimization,tree,computer-science,Algorithm,Optimization,Tree,Computer Science,大家好,我有算法问题,我努力寻找最佳解决方案。我有一棵我想穿过的树。树的节点由值和节点的秩组成(值和秩可以是随机数) 我要做的是遍历树,对于每个节点,我要对所有子节点的值求和,除了具有较低秩的子节点和它们下面的所有节点(不考虑秩)。树没有任何特殊属性,因为每个节点都可以有一个或多个子节点。关于等级或价值观,父母和子女之间的关系没有适用的规则 我最天真的解决方案是递归地遍历每个节点的子树,并在找到秩较低的节点时立即停止递归,在返回子树根的过程中求和值。然而,我觉得这是次优的解决方案(在最坏的情况下

大家好,我有算法问题,我努力寻找最佳解决方案。我有一棵我想穿过的树。树的节点由和节点的组成(值和秩可以是随机数)

我要做的是遍历树,对于每个节点,我要对所有子节点的值求和,除了具有较低秩的子节点和它们下面的所有节点(不考虑秩)。树没有任何特殊属性,因为每个节点都可以有一个或多个子节点。关于等级或价值观,父母和子女之间的关系没有适用的规则

我最天真的解决方案是递归地遍历每个节点的子树,并在找到秩较低的节点时立即停止递归,在返回子树根的过程中求和值。然而,我觉得这是次优的解决方案(在最坏的情况下-即每个节点只有一个子代-其基本链表和列组按升序排序到根-此解决方案为O(n^2))

在一次遍历之后,是否可以对所有节点求和

编辑: 这个解决方案稍微好一点,因为我的天真方法可以为每个访问的节点递归地将其值传播回根,同时保持访问节点的最小秩(在回根遍历期间)。然后仅向低于最小秩的节点添加值。

编辑 回答不正确,无法解决OP提出的问题(cf评论)
旧答案(编辑前) 您可以看到,这个问题(与树上的大多数问题一样)可以通过递归方法解决。这是因为节点的
和值
仅取决于其子节点的
和值
及其相应的
等级

下面是描述解决方案的伪代码

get_sum(my_node, result_arr):
    my_sum = 0
    for child in my_node.children():
        get_sum(child, result_arr)        // we compute the sum value of the children
        if rank(child) >= rank(my_node):  // if child node is big enough add its sum
            my_sum += result_arr[child]
     result_arr[my_node] = my_sum         // store the result somewhere

这是一个基于BFS的算法,应该在
O(n)
中运行,并使用树中的
n
节点数。要获取所有节点的值,请在树的根节点上调用此递归函数。

从我的手机编辑:因为我们只检查树根的值,所以我们可以使用不相交集结构,仅使用路径压缩,而不是动态树。不要费心更新非根

这里有一个O(nlogn)时间算法,它使用了。(我知道。实施起来很痛苦。我尽量不把它们包括在回答中。)

将节点从最大到最小排序,并使用其值初始化完全断开连接的动态树。对于顺序中的每个节点,向

  • 报告其当前值(O(对数n)摊销,最终输出该值),以及
  • 如果不是根,则将其值添加到每个祖先的值(O(logn)摊销),然后将其链接到其父级(也是O(logn)摊销)

  • 步骤2的效果是,每个节点的动态值是其子节点(相对于当前树)原始值的总和。

    我建议您使用后固定DFS。对于每个节点,保留其前一个节点的引用

    • 叶子的
      按秩求和
      是一个空目录
    • 任何节点的
      按秩求和
      是所有子节点的dict
      秩->所有子节点的值
      。如果两个或多个子节点具有相同的秩,只需添加它们的值即可
    postfixed DFS允许您自下而上计算总和

    下面是一些Python 3.7程序(代码可能未经优化):

    因此,要获得节点的
    ,只需添加与大于或等于节点秩的秩相关联的值。在Python中:

    sum(value for rank, value in node.sum_by_rank.items() where rank >= node.rank)
    

    a、b、c
    成为节点。假设
    a
    是祖先或
    b
    ,而
    b
    c
    的祖先

    观察:如果
    b.rank>c.rank
    a.rank>b.rank
    a.rank>c.rank
    。 这导致我们得出这样的结论:
    a
    sum\u-by-rank
    等于
    sum\u-by-rank(b)+b.value
    对于
    a
    的每个
    b
    直接子级,其秩低于
    a

    这表明了以下递归:

    ComputeRank(v)
        if v is null
           return
    
        let sum = 0
        foreach child in v.children
            ComputeRank(child)
            if child.rank <= v.rank 
                sum += child.sumByRank + child.value
    
        v.sumByRank = sum
    
    ComputeRank(v)
    如果v为空
    返回
    设和=0
    在v.children中foreach儿童
    电脑银行(儿童)
    
    如果child.rank谢谢你的回答@m.raynal,但这对我的情况不太合适。想象一下根为0的树,任何其他节点的秩都大于0。在根目录中,应该有来自所有节点的求和值(因为它的所有子节点都有更高的秩)。让我们假设根的子代具有秩2,所有其他子代具有秩1。根子节点中的和将为0,因为其所有子节点的秩都较低。所以我们得到状态,当我们期望根有所有节点的和,但是因为所有根子节点的和是0,我们得到0。好的,我没有很好地理解这个问题。我将编辑此解决方案以提供线性答案。@jferrad感谢您的回答,但这在我的特殊情况下不起作用-我将使用我先前评论中的示例。想象一下根为0的树,任何其他节点的秩都大于0。在根目录中,应该有来自所有节点的求和值(因为它的所有子节点都有更高的秩)。让我们假设根的子代具有秩2,所有其他子代具有秩1。根子节点中的和将为0,因为其所有子节点的秩都较低。所以当我们期望根节点有所有节点的和时,我们得到状态,但因为所有根子节点的和是0,我们得到0。@EddGarcia请参见我的编辑。解决方案是O(n),但实现可能会有所改进。@EddGarcia我认为复杂性是O(n),但我现在有一个严重的疑问,因为我们在树的每一层计算dict。
    ComputeRank(v)
        if v is null
           return
    
        let sum = 0
        foreach child in v.children
            ComputeRank(child)
            if child.rank <= v.rank 
                sum += child.sumByRank + child.value
    
        v.sumByRank = sum