For a shorter ver., only read the paragraphs that immediately follow the BOLD sentences and it reduces to only 3 paragraphs.
Problem Statement : Given a tree with N nodes rooted at node 1. Each node is associated with a value. Determine the closest ancestor that contains the value coprime to the current node value. (Note that it is node value and not node number.)
Here is my algorithm :
Define the lists as : adj[ ] is the adjacency list (a list of lists which is constructed when taking inputs from the user), vis[ ] denotes if a node is visited, children[ ] is a list of lists that stores the children of each node, when exists. Since this is a tree, we will construct adj[ ] such that adj[node] = list of children of node. This helps us with not worrying about whether a node is visited or not.
Create a list parent[ ] that stores the parent of each node. Do it as :
def search_parent(node):
for i in adj[node] :
parent[i] = node
search_parent(i)
Our main algorithm is to start at node 1 and mark it as ans[1] = -1 since it can not have an ancestor. Traverse through the nodes in the DFS manner. Check for the coprime ancestor by setting a variable v and a while loop such that if gcd(node, v) == 1 : ans[node] = v else make v = parent[v]. In this way, we check if the parent is coprime, if not, we check if parent[parent] is coprime and so on, till we hit the base case.
Pseudocode for the main problem :
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)
The code can be reduced in complexity by a constant factor if instead of list parent, we chose dictionary parent. Then when v = parent[1] is reached, we can directly make parent[1] = -1 and ans[node] = -1 is returned in the next step of the while loop, following which the while loop terminates. On the other hand, the current code goes through the if condition upto O(depth(node)) times for every node.
The GCD can be evaluated in O(log_2 max(val[node])) time. The while loop runs in a time proportional to O(depth(node)). Suppose b is the max branching factor of the graph. Then, the overall complexity will be O(|V| + |E| + sum(b^{r <= d} log_2 max(val[node]))) = O(N log_2 max(val)).
1. Is there a more optimized code (average time/space complexity wise)?
2. Is the algorithm correct or there are loop holes in the logic or maybe in some boundary cases?