【发布时间】:2021-03-23 19:33:10
【问题描述】:
对于较短的版本,只阅读紧跟粗体句子的段落,它会减少到只有 3 个段落。
问题陈述: 给定一棵树,其 N 个节点以节点 1 为根。每个节点都与一个值相关联。确定包含与当前节点值互质的值的最近祖先。 (注意是节点值,不是节点号)
这是我的算法:
将列表定义为: adj[ ] 是邻接列表(从用户获取输入时构造的列表列表), vis[ ] 表示是否访问了节点,children[ ] 是列表的列表存储每个节点的子节点(如果存在)。由于这是一棵树,我们将构造 adj[ ] 使得 adj[node] = node 的 children 列表。这有助于我们不必担心节点是否被访问。
创建一个列表 parent[ ] 来存储每个节点的父节点。这样做:
def search_parent(node):
for i in adj[node] :
parent[i] = node
search_parent(i)
我们的主要算法是从节点 1 开始并将其标记为 ans[1] = -1,因为它不能有祖先。以 DFS 方式遍历节点。通过设置变量 v 和 while 循环来检查互质祖先,使得 if gcd(node, v) == 1 : ans[node] = v else make v = parent[v]。这样,我们检查 parent 是否互质,如果不是,我们检查 parent[parent] 是否互质,依此类推,直到达到基本情况。
主要问题的伪代码:
ans[1] = -1
parent[1] = 0
def dfs(root) :
loop node in adj[root] :
v = root
while (5 > 0) :
if gcd(val[node],val[v]) == 1 :
ans[node] = v
dfs(node)
else :
v = parent[v]
if v == 0 :
ans[node] = -1
dfs(node)
如果我们选择字典父代而不是列表父代,则可以通过一个常数因子降低代码的复杂性。然后当达到 v = parent[1] 时,我们可以直接让 parent[1] = -1 并且在 while 循环的下一步返回 ans[node] = -1,然后 while 循环终止。另一方面,当前代码对每个节点都经历了 if 条件直到 O(depth(node)) 次。
可以在 O(log_2 max(val[node])) 时间内评估 GCD。 while 循环运行的时间与 O(depth(node)) 成正比。假设 b 是图的最大分支因子。然后,整体复杂度将为 O(|V| + |E| + sum(b^{r O(N log_2 max(val)) 。
1.是否有更优化的代码(平均时间/空间复杂度)?
2。算法是否正确,或者逻辑中存在漏洞,或者在某些边界情况下可能存在?
【问题讨论】:
-
1.可能值的范围是多少?如果它是较小的正整数,那可能是一种策略。如果它可能是巨大的/无限的,那么可能需要其他东西。 2. 对于给定的固定大小的已知树,这是一次操作吗?或者,即使在树中添加和删除成员或某些节点中的值发生更改时,您是否希望保持质量? 3. 树的预期大小是多少? N有多小?它有时/经常/总是很大吗? 4. 如果树或其值随时间变化,是否可以为每个节点存储额外的中间信息?
-
@Eric Arbitrary 是您所有问题的答案。
-
如果不使用
vis[],为什么要定义它? -
adj[]和children[]有什么区别 - 后者没有被使用?
标签: algorithm graph tree depth-first-search tree-traversal