Find the edge which is not a part of any possible diameter of a tree - data-structures

I'm curious if there is a quick way to find if an edge exists which is not a part of any possible diameter of a n-ary tree. For example in the following tree, A-B edge will not be a part of any diameter.
I tried by listing down all the possible diameters, but that takes a lot of time and I'm certain that there is a faster way.

Let's begin with a simpler question: how would we find any diameter of the tree? One way to do this would be to pick some node and to root the tree at that node. A diameter of the graph then could be found in one of two ways:
The diameter might purely be contained within one of those subtrees.
The diameter might be found by taking the roots of two subtrees, computing the longest path starting at each of the subtree roots, and then joining them together through the overall tree root.
So imagine that we recursively visit each subtree and obtain, from each, both the longest path starting at the root of that subtree (we could store this implicitly by having each node store its height) and the length of the longest path purely within that subtree (possibly stored implicitly by tagging each subtree with the length of the longest path within that tree). Once we have this information, we can find some diameter as follows: the diameter is either
the longest path purely within one of those subtrees, or
formed by joining two of the longest paths starting at the roots of the subtrees through the root.
All this information can be computed in time O(n) with O(n) auxiliary storage, and so if we just need to determine what the diameter is, we can do so fairly quickly.
Now, let's modify this to actually find all the edges that might get used. We can do this by starting at the root node. Consider the lengths of the paths obtained via routes (1) and (2). If route (1) produces a strictly longer path than route (2), we can recursively descend into each subtree containing a path of that length and run the same process to identify the edges that could potentially be used. If route (2) produces a strictly longer path than route (2), we'd then mark the edge from the root to each of its children who have the longest path starting at a subtree root as being used, and if there's exactly one such subtree we'd then mark each subtree tied for the second-longest path as being used. We'd then recursively descend into those subtrees, always taking paths down subtrees containing one of the many possible longest paths.
This second propagation step takes time O(n) because each node is visited exactly once and the work done is proportional to the number of children. Overall, this is an O(n)-time algorithm that uses O(n) space.

Related

Algorithm to find the longest path in binary tree?

Question:
You are given a rooted binary tree (each node has at most two children).
For a simple path p between two nodes in the tree, let mp be the node on the path that is highest
(closest to the root). Define the weight of a path w(p) = Σ_u∈p d(u, mp), where d denotes the distance
(number of edges on the path between two nodes). That is, every node on the path is weighted by the
distance to the highest node on the path.
The question asks an algorithm that finds the maximum weight among all simple paths in the tree. I'm not sure if I interpreted correctly, but can I just find the longest path from mp to the farthest node? I haven't figure out which algorithm is appropriate for this question, but I think recursive is one way to do it. Again, I don't understand the question very well, it would be better if someone could "translate" it for me and guide me to the solution.
Let's assume we know mp. Then the highest-weight path must start in the left subtree and end in the right subtree (or vice versa). Otherwise, the path would not be simple. To find the start and end node, we would go as deep as possible into the respective subtrees as each level adds depth to the weight. Therefore, we can compute the weight of this path directly from the heights of the two subtrees (by using the analytic solution of the arithmetic progression):
max_weight = height_left * (height_left + 1) / 2 + height_right * (height_right + 1) / 2
To find the maximum weight path across the entire tree (without prescribing mp), simply check this value for all nodes. I.e., take a recursive algorithm that calculates the height for each subtree. When you have the two subtree heights for a node, calculate the maximum weight. Of all these weights, take the maximum. This requires time linear in the number of nodes.
And to answer your question: No, it is not necessarily the longest path in the tree. The path can have one branch that goes very deep but a very shallow branch on the other side. This is because adding one level deeper to the path does not just increase the weight by 1 but by the depth of that node.
This problem is the diameter of a binary tree. In this case, the node that at the lower level has a greater weight because it's far from the root. Therefore, to find the longest path is to find the diameter of the binary tree. We can use brute force algorithm to solve it, by traveling all leaf-to-leaf paths, then arriving at the diameter.
Method: naive approach
Find the height of left and right subtree, and then find the left and right diameter. Return the Maximum(Diameter of left subtree, Diameter of right subtree, Longest path between two nodes which passes through the root.)
Time Complexity: Since when calculating the diameter, every iteration for every node, is calculating height of tree separately in which we iterate the tree from top to bottom and when we calculate diameter recursively so its O(N2)
Improve:
If you notice at every node to find the diameter we are calling a separate function to find the height. We can improve it by finding the height of tree and diameter in the same iteration.Every node will return the two information in the same iteration , height of that node and diameter of tree with respect to that node. Running time is O(N)

How to find the longest path that connects two leaves in a binary tree?

how can I find the length of the longest path that connects two leaves through the root in a binary tree?
The function must be recursive and it must return the length of the
longest path.
I only need the pseudo-code
I've just read that what I'm looking for is called Diameter of the tree
As a note, the diameter of a binary tree isn’t necessarily equal to the length of the longest path through the root. Consider a complete binary tree that’s been modified by having an extra node added up over the root - then the best path doesn’t pass through the root at all.
If you must pass through the root, then the longest path is the one that goes to the deepest nodes in the left and right subtrees. So think about writing a helper function that finds the deepest node in a subtree, and see if you can use this as a starting point.

How can the shortest path between two nodes in a balanced binary tree be affected by path 'weight'?

I am following an online introductory algorithms course with Udacity.
In the final assessment there is a question as follows:
In the shortest-path oracle described in Andrew Goldberg's interview,
each node has a label, which is a list of some other nodes in the
network and their distance to these nodes. These lists have the
property that:
(1) for any pair of nodes (x,y) in the network, their lists will have
at least one node z in common
(2) the shortest path from x to y will go through z. Given a graph G
that is a balanced binary tree, preprocess the graph to create such
labels for each node. Note that the size of the list in each label
should not be larger than log n for a graph of size n.
The full question can be found here.
Given the constraint of a balanced binary tree and the hint that the size should not be larger than log n, intuitively it seems that the label for a particular node would consist of all its parents (and optionally itself, if it isn't a leaf).
However some additional instructor notes in the question adds:
Write your solution to work on weighted graphs. Note that the test
given, all the edges have a weight of one - which isn't particularly
interesting.
So my question is:
How can the shortest path between two nodes in a binary tree be affected by whether the paths have weights or not?
Surely in a binary tree, the shortest path between two nodes is the unique simple path, and is unaffected by any weighting?
(unless weights can be negative and the path doesn't have to be simple in which case there is no shortest path?)
My basic solution works with the simple test provided in the question, but fails to pass the automatic grader which gives no feedback.
I'm obviously misunderstanding something, but what...
Ok, so I think my initial reaction and the obvious answer is correct:
Positive weights cannot affect the shortest path between two nodes in a binary tree.
On the other hand, weights obviously do affect the shortest 'distance' between two nodes in a binary tree as compared to simply calculating 'distance' between nodes as the number of hops.
This is what the udacity instruction was getting at.
It seems that this instruction to work with weighted binary trees was simply to enable correct automatic grading of the code which relied on using the labels to calculate the exact shortest 'distance' (which is affected by weight) as opposed to the shortest path (list of nodes) which is not.
Once I modified my algorithm to take this into account and output the correct distance, it passed the grader.

Split a tree into equal parts by deleting an edge

I am looking for an algorithm to split a tree with N nodes (where the maximum degree of each node is 3) by removing one edge from it, so that the two trees that come as the result have as close as possible to N/2. How do I find the edge that is "the most centered"?
The tree comes as an input from a previous stage of the algorithm and is input as a graph - so it's not balanced nor is it clear which node is the root.
My idea is to find the longest path in the tree and then select the edge in the middle of the longest path. Does it work?
Optimally, I am looking for a solution that can ensure that neither of the trees has more than 2N / 3 nodes.
Thanks for your answers.
I don't believe that your initial algorithm works for the reason I mentioned in the comments. However, I think that you can solve this in O(n) time and space using a modified DFS.
Begin by walking the graph to count how many total nodes there are; call this n. Now, choose an arbitrary node and root the tree at it. We will now recursively explore the tree starting from the root and will compute for each subtree how many nodes are in each subtree. This can be done using a simple recursion:
If the current node is null, return 0.
Otherwise:
For each child, compute the number of nodes in the subtree rooted at that child.
Return 1 + the total number of nodes in all child subtrees
At this point, we know for each edge what split we will get by removing that edge, since if the subtree below that edge has k nodes in it, the spilt will be (k, n - k). You can thus find the best cut to make by iterating across all nodes and looking for the one that balances (k, n - k) most evenly.
Counting the nodes takes O(n) time, and running the recursion visits each node and edge at most O(1) times, so that takes O(n) time as well. Finding the best cut takes an additional O(n) time, for a net runtime of O(n). Since we need to store the subtree node counts, we need O(n) memory as well.
Hope this helps!
If you see my answer to Divide-And-Conquer Algorithm for Trees, you can see I'll find a node that partitions tree into 2 nearly equal size trees (bottom up algorithm), now you just need to choose one of the edges of this node to do what you want.
Your current approach is not working assume you have a complete binary tree, now add a path of length 3*log n to one of leafs (name it bad leaf), your longest path will be within one of a other leafs to the end of path connected to this bad leaf, and your middle edge will be within this path (in fact after you passed bad leaf) and if you partition base on this edge you have a part of O(log n) and another part of size O(n) .

Counting the number of shortest paths through a node in a DAG

I'm looking for an algorithm to count the number of paths crossing a specific node in a DAG (similar to the concept of 'betweenness'), with the following conditions and constraints:
I need to do the counting for a set of source/destination nodes in the graph, and not all nodes, i.e. for a middle node n, I want to know how many distinct shortest paths from set of nodes S to set of nodes D pass through n (and by distinct, I mean every two paths that have at least one non-common node)
What are the algorithms you may suggest to do this, considering that the DAG may be very large but sparse in edges, and hence preference is not given to deep nested loops on nodes.
You could use a breadth first search for each pair of Src/Dest nodes and see which of those have your given node in the path. You would have to modify the search slightly such that once you've found your shortest path, you continue to empty the queue until you reach a path that causes you to increase the size. In this way you're not bound by random chance if there are multiple shortest paths. This is only an option with non-weighted graphs, of course.

Resources