weight sum for path between two nodes in a tree - algorithm

You are given a Tree with n vertices. Every node has an integer weight associated with it.
There are a huge number of queries(~n^2) on the given tree.
for a query (A, B), where A, B are two vertices of the tree, you need to calculate sum of weights of the nodes on the unique path from A to B, including A and B.
I can do dfs/bfs for individual queries but that is going to take O(n^3) for ~n^2 possible queries..
can anyone suggest something better which takes less than O(n) per query?
thanks..

If the tree is not rooted, make any arbitrary node the root of the tree.
We'll denote weight of the node x with W[x] and sum of weights of all nodes from root to node x with C[x].
Now let's assume there's a query like, u, v:
We've to find the Lowest Common Ancestor of node u and v. Let's assume the LCA of u and v is P. so the result for query (u,v) will be C[u]-C[P]+C[v]-C[P]+W[P]

Isn't your problem very similar to Timus Online Judge 1471.Tree ?
The only difference is that nodes are weighted in your problem while edges are weighted in Ural 1471.Tree.
This is a typical LCA problem.
Make anyone of the nodes as the root of the tree(if necessary), then calculate the distance dist[i] of every other nodes to the root, which takes O(N) time using BFS/DFS.
Then for each query(A,B), find the LCA L of (A,B), then the distance between of (A,B) is
dist[A] + dist[B] - 2*dist[L].
However, in your problem, it may be necessary to convert the node weight to edge weight.
If you are not familiar with the LCA algorithm, here is a very good site that may help you.

Related

Specific Graph and need to more Creative solution

Directed Graph (|V|=a, |E|=b) is given.
each vertexes has specific weight. we want for each vertex (1..a) find a vertex with maximum weight that can be reachable from that vertex.
Update 1: one nice answer is prepare by #Paul in O(b + a log a). but I
search for O(a + b) algorithms, if any?
Is there any different efficient or fastest any other ways for doing it?
Yes, it's possible to modify Tarjan's SCC algorithm to solve this problem in linear time.
Tarjan's algorithm uses two node fields to drive its SCC finding logic: index, which represents the order in which the algorithm discovers the nodes; and lowlink, the minimum index reachable by a sequence of tree arcs followed by a back arc. As part of the same depth-first traversal, we can compute another field, maxweight, which has one of two meanings:
For a node not yet included in a finished SCC, it represents the maximum weight reachable by a sequence of tree arcs, optionally followed by a cross arc to another SCC and then any subsequent path.
For nodes in a finished SCC, it represents the maximum weight reachable.
The logic for computing maxweight is as follows. If we discover an arc from v to a new node w, then vw is a tree arc, so we compute w.maxweight recursively and update v.maxweight = max(v.maxweight, w.maxweight). If w is on the stack, then we do nothing, because vw is a back arc and not included in the definition of maxweight. Otherwise, vw is a cross arc, and we do the same update that we would have done for a tree arc, just without the recursive call.
When Tarjan's algorithm identifies an SCC, it's because it has a node r with r.lowlink == r.index. Since r is the depth-first search root of this SCC, its value of maxweight is correct for the whole SCC. Instead of recording each node in the SCC, we simply update its maxweight to r.maxweight.
Sort all nodes by weight in decreasing order and create the graph g' with all edges in E reversed (i.e. if there's an edge a -> b in g, there's an edge b -> a in g'). In this graph you can now propagate the maximum-value by simple DFS. Do this iteratively for all nodes and terminate when a maximum-weight has already been assigned.
As pseudocode:
dfs_assign_weight_reachable(node, weight):
if node.max_weight_reachable >= weight:
return
node.max_weight_reachable = weight
for n = neighbor of node:
dfs_assign_weight_reachable(n, weight)
g' = g with all edges reversed
nodes = nodes from g' sorted descendingly by weight
assign max_weight_reachable = -inf to each node in nodes
for node in nodes:
dfs_assign_weight_reachable(node, node.weight)
UPDATE:
The tight bound is O(b + a log a). a log a is caused by the sorting step. And each edge gets visited once during the reversal step and once during the assigning maximum weights, giving the second term in the max-expression.
Acknowledgement:
I'd like to thank #SerialLazer for the time invested in a discussion about the time-complexity of the above algorithm and helping me figure out the correct bound.

Set of Least Common Ancestors in a Directed Acyclic Graph

I have a hierarchy of nodes that I need to use for an analysis. Sort of like this
I'm trying to find an algorithm that will allow me to find the nearest common ancestors between two nodes. I know there are algorithms that find the lowest common ancestor, but I haven't been able to find one that allows us to find the nearest few.
For example, in the picture I linked above, if I give it two nodes: 0 and 1, it should return 2 and 5. i.e. It should return all common ancestors of the nodes that don't have descendants that are also common ancestors. A naive approach would be to get all the common ancestors of 0 and 1: {7, 5, 6, 3, 2}, and then eliminate 7 since it has descendants in the set. Then it'll eliminate 6 and 3 as well. So it would return SLCA = {5,2}. At the moment, I've stored all the ancestors of each node in a list. So this naive approach is possible. However, I'd like do a more efficient method that will be scalable for even very large graphs. Ultimately, for a given graph, I'd like to be able to compute the pairwise SLCA of each pair of nodes. I think this brute force approach would be slow for very large graphs.
Does anyone know of such an algorithm? I've been reading these papers, but they are pretty dense, and I've been stuck trying to understand them.
https://www.dcs.warwick.ac.uk/~czumaj/PUBLICATIONS/DRAFTS/LCA-Max-witness.pdf
http://www.ccs.neu.edu/home/dherman/browse/projects/mini-javac/papers/bender01finding.pdf
https://algo2.iti.kit.edu/download/fischer10new.pdf
https://algo2.iti.kit.edu/download/fischer10new.pdf
I appreciate the help
Well actually your "brute force" algorithm is quite efficient. Let's analyze it:
Finding all of the common ancestors, you can do this with two BFS and an array that keep the node which are in both trees: Time - O(V + E), Memory: O(V).
Now you can find all of the ancestors which do not have descendants in the group, which are all the nodes that are the closest to the roots. This will not take long, take the sub graph of this group and find a node with no incoming edges in O(V + E) time (By iterating over the nodes), and O(V) memory. This will be your answer.
So in total - Time O(V + E), Memory O(V).
The next answer is not the correct answer, it finds the closest common ancestor (I have written it by mistake and I don't really want to delete it):
Duplicate the graph, now we have G1 and G2. For each node in G1 create a new edge over to the corresponding node in G2. 'Flip' all the edges in G2 - if there was an edge from v to u now it's from u to v.
Call this new graph G, call the two nodes you need to find the SLCA u and v.
It is easy to show that the shortest route from u in G1 to the corresponding v in G2 will pass through an edge from G1 to G2 and that the node of this edge (both nodes on this edge are corresponding) will be in the SLCA group.
That is since if you look at the original graph, the paths we took from each node v, u is the shortest to meet, which is the definition of the SLCA group.
Now you need to find all the path of the shortest path length and extract all of these nodes.
Time: O(E + V) (shortest path - BFS)
Memory: O(V) (BFS)

graph - The implementation of updating Minimum Spanning Tree after adding a new edge

Here is an excise
Suppose we are given the minimum spanning tree T of a given graph G
(with n vertices and m edges) and a new edge e = (u, v) of weight w
that we will add to G. Give an efficient algorithm to find the minimum
spanning tree of the graph G + e. Your algorithm should run in O(n)
time to receive full credit.
I have this idea:
In the MST, just find out the path between u and v. Then find the edge (along the path) with maximum weight; if the maximum weight is bigger than w, then remove that edge from the MST and add the new edge to the MST.
The tricky part is how to do this in O(n) time and it is also I get stuck.
The question is that how the MST is stored. In normal Prim's algorithm, the MST is stored as a parent array, i.e., each element is the parent of the according vertex.
So suppose the excise give me a parent array indicating the MST, how can I release the above algorithm in O(n)?
First, how can I identify the path between u and v from the parent array? I can have two ancestor arrays for u and v, then check on the common ancestor, then I can get the path, although in backwards. I think for this part, to find the common ancestor, at least I have to do it in O(n^2), right?
Then, we have the path. But we still need to find the weight of each edge along the path. Since I suppose the graph will use adjacency-list for Prim's algorithm, we have to do O(m) (m is the number of edges) to locate each weight of the edge.
...
So I don't see it is possible to do the algorithm in O(n). Am I wrong?
The idea you have is right. Note that, finding the path between u and v is O(n). I'll assume you have a parent array identifying the MST. tracking the path (for max edge) from u to v or u to root vertex should take only O(n). If you reach root vertex, just track the path from v to u or root vertex.
Now that you have the path from u -> u1 ... -> max_path_vert1 -> max_path_vert2 -> ... -> v, remove the edge max_path_vert1->max_path_vert2 (assuming this is greater than the added edge) and reverse the parents for u->...->max_path_vert1 and mark parent[u] = v.
Edit: More explanation for clarity
Note that, in MST there will be exactly one path between any pair of vertices. So, if you can trace from u->y and v->y, you have only traced through atmost n vertices. If you traced more than n vertices that means you visited a vertex twice, which will not happen in an MST. Ok, now hopefully you're convinced it's O(n) to track from u->y and v->y. Once you have these paths, you have established a path from u->v. Do you see how? I'm assuming this is an undirected graph, since finding MST for directed graph is a different concept in itself. For undirected graph, when you have a path from x->y you have a path from y-x. So, u->y->v exist. You don't even need to trace back from y->v, since weights for v->y will be same as that of y->v. Just find the edge with the maximum weight when you trace from u->y and v->y.
Now for finding edge weights in O(1); how are you storing your current weights? Adjacency list or adjacency matrix? For O(1) access, store it the way parent vertex array is stored. So, weight[v] = weight(v, parent[v]). So, you'll have O(1) access. Hope this helps.
Well - your solution is correct.
But regarding implementation, I dont see why you are using G instead of T to find the path between u and v. Using any search traversal in T for the path between u and v, will give you O(n). - That is, you can assume that v is the root and performs a Depth-First Search algorithm [in this case, you will have to assume all neighbors of v as children] - and stop the DFS once you find u - then, the nodes in the stack corresponds to the path between u and v.
It is easy afterward to find the cost of each edge in the path (O(n)), and it is easy as well to delete/add edges. In total O(n).
Does that help somehow ?
Or maybe you are getting O(n^2) - according to my understanding - because you access the children of a vertex v in T in O(n) -- Here, you have to present your data structure as a mapped array so that the cost is reduced to O(1). [for instace, {a,b,c,u,w}(vertices) -> {0,1,2,3,4}(indices of vertices).

Using a minimum spanning tree algorithm

Suppose I have a weighted non-directed graph G = (V,E). Each vertex has a list of elements.
We start in a vertex root and start looking for all occurances of elements with a value x. We wish to travel the least amount of distance (in terms of edge weight) to uncover all occurances of elements with value x.
The way I think of it, a MST will contain all vertices (and hence all vertices that satisfy our condition). Therefore the algorithm to uncover all occurances can just be done by finding the shortest path from root to all other vertices (this will be done on the MST of course).
Edit :
As Louis pointed out, the MST will not work in all cases if the root is chosen arbitrarily. However, to make things clear, the root is part of the input and therefore there will be one and only one MST possible (given that the edges have distinct weights). This spanning tree will indeed have all minimum-cost paths to all other vertices in the graph starting from the root.
I don't think this will work. Consider the following example:
x
|
3
|
y--3--root
| /
5 3
| /
| /
x
The minimum spanning tree contains all three edges with weight 3, but this is clearly not the optimum solution.
If I understand the problem correctly, you want to find the minimum-weight tree in the graph which includes all vertices labeled x. (That is, the correct answer would have total weight 8, and would be the two edges drawn vertically in this drawing.) But this does not include your arbitrarily selected root at all.
I am pretty confident that the following variation on Prim's algorithm would work. Not sure if it's optimal, though.
Let's say the label we are looking for is called L.
Use an all-pairs shortest path algorithm to compute d(v, w) for all v, w.
Pick some node labeled L; call this the root. (We can be sure that this will be in the result tree, since we are including all nodes labeled L.)
Initialize a priority queue with the root initialized to 0. (The priority queue will consist of vertices labeled L, and their minimum distance from any node in the tree, including vertices not labeled L.)
While the priority queue is nonempty, do the following:
Pick out the top vertex in the queue; call it v, and its distance from the tree d.
For each vertex w on the path from v to the tree, v inclusive, find the nearest L-labeled node x to w, and add x to the priority queue, or update its priority. Add w to the tree.
The answer is no, if I'm understanding correctly. Finding the minimum spanning tree will contain all vertices V, but you only want to find the vertices with value x. Thus, your MST result may have unneeded vertices adding extra path length and therefore be sub-optimal.
An example has been given where the MST M1 from Root differs from an MST M2 containing all x nodes but not containing Root.
Here's an example where Root is in both MST's: Let graph G contain nodes R,S,T,U,V (R=Root), and a clockwise path R-S-T-U-V-R, with edge weights 1,1,3,2,2 going clockwise, and x at R, S, T, U. The first MST, M1, will have subtrees S-T and V-U below R, with cost 6 = 2+4, and cost-3 edge T-U not included in M1. But M2 has subtree S-T-U (only) below R, at cost 5.
Negative. If the idea is to find for every node that contains 'x' a separate path from root to it, and minimize the total cost of the paths, then you can just use simple shortest-path calculation separately for every node starting from the root, and put the paths together.
Some of those shortest paths will not be in the minimum spanning tree, so if this is your goal, the MST solution does not work. MST optimizes the cost of the tree, not the sum of costs of paths from root to the nodes.
If your idea is to find one path that starts from root and traverses through all nodes that contain 'x', then this is the traveling salesman problem and it is an NP-complete optimization problem, i.e. very hard.

minimum connected subgraph containing a given set of nodes

I have an unweighted, connected graph. I want to find a connected subgraph that definitely includes a certain set of nodes, and as few extras as possible. How could this be accomplished?
Just in case, I'll restate the question using more precise language. Let G(V,E) be an unweighted, undirected, connected graph. Let N be some subset of V. What's the best way to find the smallest connected subgraph G'(V',E') of G(V,E) such that N is a subset of V'?
Approximations are fine.
This is exactly the well-known NP-hard Steiner Tree problem. Without more details on what your instances look like, it's hard to give advice on an appropriate algorithm.
I can't think of an efficient algorithm to find the optimal solution, but assuming that your input graph is dense, the following might work well enough:
Convert your input graph G(V, E) to a weighted graph G'(N, D), where N is the subset of vertices you want to cover and D is distances (path lengths) between corresponding vertices in the original graph. This will "collapse" all vertices you don't need into edges.
Compute the minimum spanning tree for G'.
"Expand" the minimum spanning tree by the following procedure: for every edge d in the minimum spanning tree, take the corresponding path in graph G and add all vertices (including endpoints) on the path to the result set V' and all edges in the path to the result set E'.
This algorithm is easy to trip up to give suboptimal solutions. Example case: equilateral triangle where there are vertices at the corners, in midpoints of sides and in the middle of the triangle, and edges along the sides and from the corners to the middle of the triangle. To cover the corners it's enough to pick the single middle point of the triangle, but this algorithm might choose the sides. Nonetheless, if the graph is dense, it should work OK.
The easiest solutions will be the following:
a) based on mst:
- initially, all nodes of V are in V'
- build a minimum spanning tree of the graph G(V,E) - call it T.
- loop: for every leaf v in T that is not in N, delete v from V'.
- repeat loop until all leaves in T are in N.
b) another solution is the following - based on shortest paths tree.
- pick any node in N, call it v, let v be a root of a tree T = {v}.
- remove v from N.
loop:
1) select the shortest path from any node in T and any node in N. the shortest path p: {v, ... , u} where v is in T and u is in N.
2) every node in p is added to V'.
3) every node in p and in N is deleted from N.
--- repeat loop until N is empty.
At the beginning of the algorithm: compute all shortest paths in G using any known efficient algorithm.
Personally, I used this algorithm in one of my papers, but it is more suitable for distributed enviroments.
Let N be the set of nodes that we need to interconnect. We want to build a minimum connected dominating set of the graph G, and we want to give priority for nodes in N.
We give each node u a unique identifier id(u). We let w(u) = 0 if u is in N, otherwise w(1).
We create pair (w(u), id(u)) for each node u.
each node u builds a multiset relay node. That is, a set M(u) of 1-hop neigbhors such that each 2-hop neighbor is a neighbor to at least one node in M(u). [the minimum M(u), the better is the solution].
u is in V' if and only if:
u has the smallest pair (w(u), id(u)) among all its neighbors.
or u is selected in the M(v), where v is a 1-hop neighbor of u with the smallest (w(u),id(u)).
-- the trick when you execute this algorithm in a centralized manner is to be efficient in computing 2-hop neighbors. The best I could get from O(n^3) is to O(n^2.37) by matrix multiplication.
-- I really wish to know what is the approximation ration of this last solution.
I like this reference for heuristics of steiner tree:
The Steiner tree problem, Hwang Frank ; Richards Dana 1955- Winter Pawel 1952
You could try to do the following:
Creating a minimal vertex-cover for the desired nodes N.
Collapse these, possibly unconnected, sub-graphs into "large" nodes. That is, for each sub-graph, remove it from the graph, and replace it with a new node. Call this set of nodes N'.
Do a minimal vertex-cover of the nodes in N'.
"Unpack" the nodes in N'.
Not sure whether or not it gives you an approximation within some specific bound or so. You could perhaps even trick the algorithm to make some really stupid decisions.
As already pointed out, this is the Steiner tree problem in graphs. However, an important detail is that all edges should have weight 1. Because |V'| = |E'| + 1 for any Steiner tree (V',E'), this achieves exactly what you want.
For solving it, I would suggest the following Steiner tree solver (to be transparent: I am one of the developers):
https://scipjack.zib.de/
For graphs with a few thousand edges, you will usually get an optimal solution in less than 0.1 seconds.

Resources