Algorithm 条件下树遍历和节点值求和的最优解
大家好,我有算法问题,我努力寻找最佳解决方案。我有一棵我想穿过的树。树的节点由值和节点的秩组成(值和秩可以是随机数) 我要做的是遍历树,对于每个节点,我要对所有子节点的值求和,除了具有较低秩的子节点和它们下面的所有节点(不考虑秩)。树没有任何特殊属性,因为每个节点都可以有一个或多个子节点。关于等级或价值观,父母和子女之间的关系没有适用的规则 我最天真的解决方案是递归地遍历每个节点的子树,并在找到秩较低的节点时立即停止递归,在返回子树根的过程中求和值。然而,我觉得这是次优的解决方案(在最坏的情况下-即每个节点只有一个子代-其基本链表和列组按升序排序到根-此解决方案为O(n^2)) 在一次遍历之后,是否可以对所有节点求和 编辑: 这个解决方案稍微好一点,因为我的天真方法可以为每个访问的节点递归地将其值传播回根,同时保持访问节点的最小秩(在回根遍历期间)。然后仅向低于最小秩的节点添加值。编辑 回答不正确,无法解决OP提出的问题(cf评论)Algorithm 条件下树遍历和节点值求和的最优解,algorithm,optimization,tree,computer-science,Algorithm,Optimization,Tree,Computer Science,大家好,我有算法问题,我努力寻找最佳解决方案。我有一棵我想穿过的树。树的节点由值和节点的秩组成(值和秩可以是随机数) 我要做的是遍历树,对于每个节点,我要对所有子节点的值求和,除了具有较低秩的子节点和它们下面的所有节点(不考虑秩)。树没有任何特殊属性,因为每个节点都可以有一个或多个子节点。关于等级或价值观,父母和子女之间的关系没有适用的规则 我最天真的解决方案是递归地遍历每个节点的子树,并在找到秩较低的节点时立即停止递归,在返回子树根的过程中求和值。然而,我觉得这是次优的解决方案(在最坏的情况下
旧答案(编辑前) 您可以看到,这个问题(与树上的大多数问题一样)可以通过递归方法解决。这是因为节点的
和值
仅取决于其子节点的和值
及其相应的等级
下面是描述解决方案的伪代码
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)时间算法,它使用了。(我知道。实施起来很痛苦。我尽量不把它们包括在回答中。)
将节点从最大到最小排序,并使用其值初始化完全断开连接的动态树。对于顺序中的每个节点,向
步骤2的效果是,每个节点的动态值是其子节点(相对于当前树)原始值的总和。我建议您使用后固定DFS。对于每个节点,保留其前一个节点的引用
- 叶子的
是一个空目录李>按秩求和
- 任何节点的
是所有子节点的dict按秩求和
。如果两个或多个子节点具有相同的秩,只需添加它们的值即可秩->所有子节点的值
和
,只需添加与大于或等于节点秩的秩相关联的值。在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