What is a good algorithm for getting the minimum vertex cover of a tree? - algorithm

What is a good algorithm for getting the minimum vertex cover of a tree?
INPUT:
The node's neighbours.
OUTPUT:
The minimum number of vertices.

I didn't fully understand after reading the answers here, so I thought I'd post one from here
The general idea is that you root the tree at an arbitrary node, and ask whether that root is in the cover or not. If it is, then you calculate the min vertex cover of the subtrees rooted at its children by recursing. If it isn't, then every child of the root must be in the vertex cover so that every edge between the root and its children is covered. In this case, you recurse on the root's grandchildren.
So for example, if you had the following tree:
A
/ \
B C
/ \ / \
D E F G
Note that by inspection, you know the min vertex cover is {B, C}. We will find this min cover.
Here we start with A.
A is in the cover
We move down to the two subtrees of B and C, and recurse on this algorithm. We can't simply state that B and C are not in the cover, because even if AB and AC are covered, we can't say anything about whether we will need B and C to be in the cover or not.
(Think about the following tree, where both the root and one of its children are in the min cover ({A, D})
A
/|\___
B C D
/|\
E F G
)
A is not in the cover
But we know that AB and AC must be covered, so we have to add B and C to the cover. Since B and C are in the cover, we can recurse on their children instead of recursing on B and C (even if we did, it wouldn't give us any more information).
"Formally"
Let C(x) be the size of the min cover rooted at x.
Then,
C(x) = min (
1 + sum ( C(i) for i in x's children ), // root in cover
len(x's children) + sum( C(i) for i in x's grandchildren) // root not in cover
)

T(V,E) is a tree, which implies that for any leaf, any minimal vertex cover has to include either the leaf or the vertex adjacent to the leaf. This gives us the following algorithm to finding S, the vertex cover:
Find all leaves of the tree (BFS or DFS), O(|V|) in a tree.
If (u,v) is an edge such that v is a leaf, add u to the vertex cover, and prune (u,v). This will leave you with a forest T_1(V_1,E_1),...,T_n(U_n,V_n).
Now, if V_i={v}, meaning |V_i|=1, then that tree can be dropped since all edges incident on v are covered. This means that we have a termination condition for a recursion, where we have either one or no vertices, and we can compute S_i as the cover for each T_i, and define S as all the vertices from step 2 union the cover of each T_i.
Now, all that remains is to verify that if the original tree has only one vertex, we return 1 and never start the recursion, and the minimal vertex cover can be computed.
Edit:
Actually, after thinking about it for a bit, it can be accomplished with a simple DFS variant.

I hope here you can find more related answer to your question.
I was thinking about my solution, probably you will need to polish it but as long as dynamic programing is in one of your tags you probably need to:
For each u vertex define S+(u) is
cover size with vertex u and S-(u)
cover without vertex u.
S+(u)= 1 + Sum(S-(v)) for each child v of u.
S-(u)=Sum(max{S-(v),S+(v)}) for each child v of u.
Answer is max(S+(r), S-(r)) where r is root of your tree.
After reading this. Changed the above algorithm to find maximum independent set, since in wiki article stated
A set is independent if and only if its complement is a vertex cover.
So by changing min to max we can find the maximum independent set and by compliment the minimum vertex cover, since both problem are equivalent.

{- Haskell implementation of Artem's algorithm -}
data Tree = Branch [Tree]
deriving Show
{- first int is the min cover; second int is the min cover that includes the root -}
minVC :: Tree -> (Int, Int)
minVC (Branch subtrees) = let
costs = map minVC subtrees
minWithRoot = 1 + sum (map fst costs) in
(min minWithRoot (sum (map snd costs)), minWithRoot)

We can use a DFS based algorithm to solve this probelm:
DFS(node x)
{
discovered[x] = true;
/* Scan the Adjacency list for the node x*/
while((y = getNextAdj() != NULL)
{
if(discovered[y] == false)
{
DFS(y);
/* y is the child of node x*/
/* If child is not selected as a vertex for minimum selected cover
then select the parent */
if(y->isSelected == false)
{
x->isSelected = true;
}
}
}
}
The leaf node will never be selected for the vertex cover.

We need to find the minimum vertex cover for each node we have to choices to make, either to include it or not to include it. But according to the problem for each edge (u, v), either of 'u' or 'v' should be in the cover so we need to take care that if the current vertex is not included then we should include its children, and if we are including the current vertex then, we may or may not include its children based on optimal solution.
Here, DP1[v] for any vertex v = When we include it.
DP2[v] for any vertex v = when we don't include it.
DP1[v] = 1 + sum(min(DP2[c], DP1[c])) - this means include current and may or may not include its children, based on what is optimal.
DP2[v] = sum(DP1[c]) - this means not including current then we need to include children of current vertex. Here, c is the child of vertex v.
Then, our solution is min(DP1[root], DP2[root])
#include <bits/stdc++.h>
using namespace std;
vector<vector<int> > g;
int dp1[100010], dp2[100010];
void dfs(int curr, int p){
for(auto it : g[curr]){
if(it == p){
continue;
}
dfs(it, curr);
dp1[curr] += min(dp1[it], dp2[it]);
dp2[curr] += dp1[it];
}
dp1[curr] += 1;
}
int main(){
int n;
cin >> n;
g.resize(n+1);
for(int i=0 ; i<n-1 ; i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
cout << min(dp1[1], dp2[1]);
return 0;
}

I would simply use a linear program to solve the minimum vertex cover problem.
A formulation as an integer linear program could look like the one given here: ILP formulation
I don't think that your own implementation would be faster than these highly optimized LP solvers.

Related

Count triangles (cycles of length 3) in a graph

In an undirected graph with V vertices and E edges how would you count the number of triangles in O(|V||E|)? I see the algorithm here but I'm not exactly sure how that would be implemented to achieve that complexity. Here's the code presented in that post:
for each edge (u, v):
for each vertex w:
if (v, w) is an edge and (w, u) is an edge:
return true
return false
Would you use an adjacency list representation of the graph to traverse all edges in the outer loop and then an adjacency matrix to check for the existence of the 2 edges in the inner loop?
Also, I saw a another solution presented as O(|V||E|) which involves performing a depth-first search on the graph and when you encounter a backedge (u,v) from the vertex u you're visiting check if the grandparent of the vertex u is vertex v. If it is then you have found a triangle. Is this algorithm correct? If so, wouldn't this be O(|V|+|E|)? In the post I linked to there is a counterexample for the breadth-first search solution offered up but based on the examples I came up with it seems like the depth-first search method I outlined above works.
Firstly, note that the algorithm does not so much count the number of triangles, but rather returns whether one exists at all.
For the first algorithm, the analysis becomes simple if we assume that we can do the lookup of (a, b) is an edge in constant time. (Since we loop over all vertices for all edges, and only do something with constant time we get O(|V||E|*1). ) Telling whether something is a member of a set in constant time can be done using for example a hashtable/set. We could also, as you said, do this by the use of the adjacency matrix, which we could create beforehand by looping over all the edges, not changing our total complexity.
An adjacency list representation for looping over the edges could perhaps be used, but traversing this may be O(|V|+|E|), giving us the total complexity O(|V||V| + |V||E|) which may be more than we wanted. If that is the case, we should instead loop over this first, and add all our edges to a normal collection (like a list).
For your proposed DFS algorithm, the problem is that we cannot be sure to encounter a certain edge as a backedge at the correct moment, as is illustrated by the following counterexample:
A -- B --- C -- D
\ / |
E ----- F
Here if we look from A-B-C-E, and then find the backedge E-B, we correctly find the triangle; but if we instead go A-B-C-D-F-E, the backedges E-B, and E-C, do no longer satisfy our condition.
This is a naive approach to count the number of cycles.
We need the input in the form of an adjacency matrix.
public int countTricycles(int [][] adj){
int n = adj.length;
int count = 0;
for(int i = 0; i < n ;i++){
for(int j = 0; j < n; j++){
if(adj[i][j] != 0){
for(int k = 0; k < n; k++){
if(k!=i && adj[j][k] != 0 && adj[i][k] != 0 ){
count++;
}
}
}
}
}
return count/6;
}
The complexity would be O(n^3).

Check if all given vertices are on a path

The problem is
Given a graph and N sets of vertices, how to check that if the vertices
in each set exist on a path (that may not have to be simple) in the
graph.
For example, if a set of vertices is {A, B, C}
1) On a graph
A --> B --> C
The vertices A, B and C are on a path
2) On a graph
A ---> B ---> ...
^
C -----+
The vertices A, B and C are not on a path
3) On a graph
A <--- B <--- ...
|
C <----+
The vertices A, B and C are not on a path
4) On a graph
A ---> X -----> B ---> C --> ...
| ^
+---------------+
The vertices A, B and C are on a path
Here is a simple algorithm with complexity N * (V + E).
for each set S of vertices with more than 1 elements {
initialize M that maps a vertice to another vertice it reaches;
mark all vertices of G unvisited;
pick and remove a vertex v from S;
while S is not empty {
from all unvisited node, find one vertex v' in S that v can reach;
if v' does not exist {
pick and remove a vertex v from S;
continue;
}
M[v] = v';
remove v' from S;
v = v';
}
// Check that the relations in M forms a path
{
if size[M] != size(S)-1 {
return false;
}
take the vertex v in S that is not in M
while M is not empty {
if not exist v' s.t. M[v]' = v {
return false;
}
}
return true;
}
}
The for-loop takes N step; the while-loop would visit all node/edge in the worst case with cost V + E.
Is there any known algorithm to solve the problem?
If a graph is DAG, could we have a better solution?
Thank you
Acyclicity here is not a meaningful assumption, since we can merge each strong component into one vertex. The paths are a red herring too; with a bunch of two-node paths, we're essentially making a bunch of reachability queries in a DAG. Doing this faster than O(n2) is thought to be a hard problem: https://cstheory.stackexchange.com/questions/25298/dag-reachability-with-on-log-n-space-and-olog-n-time-queries .
You should check out the Floyd-Warshall algorithm. It will give you the lengths of the shortest path between all pairs of vertices in the graph in O(V3). Once you have those results, you can do a brute-force depth-first traversal to determine whether you can go from one node to the next and the next etc. That should happen in O(nn) where n is the number of vertices in your current set. Total complexity, then, should be O(V3 + N*nn) (or something like that).
The nn seems daunting, but if n is small compared to V it won't be a big deal in practice.
I can guess that one could improve on that given certain restrictions on the graph.

Tarjan's lowest common ancestor algorithm explanation

I am having a tough time understanding Tarjan's lowest common ancestor algorithm. Can somebody explain it with an example?
I am stuck after the DFS search, what exactly does the algorithm do?
My explanation will be based on the wikipedia link posted above :).
I assumed that you already know about the union disjoint structure using in the algorithm.
(If not please read about it, you can find it in "Introduction to Algorithm").
The basic idea is every times the algorithm visit a node x, the ancestor of all its descendants will be that node x.
So to find a Least common ancestor (LCA) r of two nodes (u,v), there will be two cases:
Node u is a child of node v (vice versa), this case is obvious.
Node u is ith branch and v is the jth branch (i < j) of node r, so after visit node u, the algorithm backtrack to node r, which is the ancestor of the two nodes, mark the ancestor of node u as r and go to visit node v.
At the moment it visit node v, as u is already marked as visited (black), so the answer will be r. Hope you get it!
I will explain using the code from CP-Algorithms:
void dfs(int v)
{
visited[v] = true;
ancestor[v] = v;
for (int u : adj[v]) {
if (!visited[u]) {
dfs(u);
union_sets(v, u);
ancestor[find_set(v)] = v;
}
}
for (int other_node : queries[v]) {
if (visited[other_node])
cout << "LCA of " << v << " and " << other_node
<< " is " << ancestor[find_set(other_node)] << ".\n";
}
}
Let's outline a proof of the algorithm.
Lemma 1: For each vertex v and its parent p, after we visit v from p and union v with p, p and all vertices in the subtree of root v (i.e. p and all descendents of v, including v) will be in one disjoint set represented by p (i.e. ancester[root of the disjoint set] is p).
Proof: Suppose the tree has height h. Then proceed by induction in vertex height, starting from the leaf nodes.
Lemma 2: For each vertex v, right before we mark it as visited, the following statements are true:
Each v's parents pi will be in a disjoint set that contains precisely pi and all vertices in the subtrees of pi that pi has already finished visiting.
Every visited vertex so far is in one of these disjoint sets.
Proof: We proceed by induction. The statement is vacuously true for the root (the only vertex with height 0) as it has no parent. Now suppose the statement holds for every vertex of height k for k ≥ 0, and suppose v is a vertex of height k + 1. Let p be v's parent. Before p visits v, suppose it has already visited its children c1, c2, ..., cn. By Lemma 1, p and all vertices in the subtrees of root c1, c2, ..., cn are in one disjoint set represented by p. Furthermore, all newly visited vertices after we visited p are the vertices in this disjoint set. Since p is of height k, we can use the induction hypothesis to conclude that v indeed satisfies 1 and 2.
We are now ready to prove the algorithm.
Claim: For each query (u,v), the algorithm outputs the lowest common ancester of u and v.
Proof: Without loss of generality suppose we visit u before we visit v in the DFS. Then either v is a descendent of u or not.
If v is a descedent of u, by Lemma 1 we know that u and v are in one disjoint set that is represented by u, which means ancestor[find_set(v)] is u, the correct answer.
If v is not a descendent of u, then by Lemma 2 we know that u must be in one of the disjoint sets, each of them represented by a parent of v at the time we mark v. Let p be the representing vertex of the disjoint set u is in. By Lemma 2 we know p is a parent of v, and u is in a visited subtree of p and therefore a descendent of p. These are not changed after we have visited all v's children, so p is indeed a common ancestor of u and v. To see p is the lowest common ancestor, suppose q is the child of p of which v is a descendent (i.e. if we travel back to root from v, q is the last parent before we reach p; q can be v). Suppose for contradiction that u is also a descendent of q. Then by Lemma 2 u is in both the disjoint set represented by p and the disjoint set represented by q, so this disjoint set contains two v's parents, a contradiction.

Finding "Best Roots" in a Directed Tree Graph?

(This is derived from a recently completed programming contest)
You are given G, a connected graph with N nodes and N-1 edges.
(Notice that this implies G forms a tree.)
Each edge of G is directed. (not necessarily upward to any root)
For each vertex v of G it is possible to invert zero or more edges such that there is a directed path from every other vertex w to v. Let the minimum possible number of edge inversions to achieve this be f(v).
By what linear or loglinear algorithm can we determine the subset of vertexes that have the minimal overall f(v) (including the value of f(v) of those vertexes)?
For example consider the 4 vertex graph with these edges:
A<--B
C<--B
D<--B
The value of f(A) = 2, f(B) = 3, f(C) = 2 and f(D) = 2...
..so therefore the desired output is {A,C,D} and 2
(note we only need to calculate the f(v) of vertexes that have a minimal f(v) - not all of them)
Code:
For posterity here is the code of solution:
int main()
{
struct Edge
{
bool fwd;
int dest;
};
int n;
cin >> n;
vector<vector<Edge>> V(n+1);
rep(i, n-1)
{
int src, dest;
scanf("%d %d", &src, &dest);
V[src].push_back(Edge{true, dest});
V[dest].push_back(Edge{false, src});
}
vector<int> F(n+1, -1);
vector<bool> done(n+1, false);
vector<int> todo;
todo.push_back(1);
done[1] = true;
F[1] = 0;
while (!todo.empty())
{
int next = todo.back();
todo.pop_back();
for (Edge e : V[next])
{
if (done[e.dest])
continue;
if (!e.fwd)
F[1]++;
done[e.dest] = true;
todo.push_back(e.dest);
}
}
todo.push_back(1);
while (!todo.empty())
{
int next = todo.back();
todo.pop_back();
for (Edge e : V[next])
{
if (F[e.dest] != -1)
continue;
if (e.fwd)
F[e.dest] = F[next] + 1;
else
F[e.dest] = F[next] - 1;
todo.push_back(e.dest);
}
}
int minf = INT_MAX;
rep(i,1,n)
chmin(minf, F[i]);
cout << minf << endl;
rep(i,1,n)
if (F[i] == minf)
cout << i << " ";
cout << endl;
}
I think that the following algorithm works correctly, and it certainly works in linear time.
The motivation for this algorithm is the following. Let's suppose that you already know the value of f(v) for some single node v. Now, consider any node u adjacent to v. If we want to compute the value of f(u), we can reuse some of the information from f(v) in order to compute it. Note that in order to get from any node w in the graph to u, one of two cases must happen:
That path passes through the edge connecting u and v. In that case, the way that we get from w to u is to go from w to v, then to follow the edge from v to u.
That path does not pass through the edge connecting u and v. In that case, the way that we get from w to u is the exact same way that we got from w to v, except that we stop as soon as we get to u.
The reason that this observation is important is that it means that if we know the number of edges we'd flip to get from any node to v, we can easily modify it to get the set of edges that we'd flip to get from any node to u. Specifically, it's going to be the same set of edges as before, except that we want to direct the edge connecting u and v so that it connects v to u rather than the other way around.
If the edge from u to v is initially directed (u, v), then we have to flip all the normal edges we flipped to get every node pointing at v, plus one more edge to get v pointed back at u. Thus f(u) = f(v) + 1. Otherwise, if the edge is originally directed (v, u), then the set of edges that we'd flip would be the same as before (pointing everything at v), except that we wouldn't flip the edge (v, u). Thus f(u) = f(v) - 1.
Consequently, once we know the value of f for a single node v, we can compute it for each adjacent node u as follows:
f(u) = f(v) + 1 if (u, v) is an edge.
f(u) = f(v) - 1 otherwise
This means that we can compute f(v) for all nodes v as follows:
Compute f(v) for some initial node v, chosen arbitrarily.
Do a DFS starting from v. When reaching a node u, compute its f score using the above logic.
All that's left to do is to compute f(v) for some initial node. To do this, we can run a DFS from v outward. Every time we see an edge pointed the wrong way, we have to flip it. Thus the initial value of f(v) is given by the number of wrong-pointing edges we find during the initial DFS.
We thus can compute the f score for each node in O(n) time by doing an initial DFS to compute f(v) for the initial node, then a secondary DFS to compute f(u) for each other node u. You can then for-loop over each of the n f-scores to find the minimum score, then do one more loop to find all values with that f-score. Each of these steps takes O(n) time, so the overall algorithm takes O(n) time as well.
Hope this helps! This was an awesome problem!

Finding the heaviest length-constrained path in a weighted Binary Tree

UPDATE
I worked out an algorithm that I think runs in O(n*k) running time. Below is the pseudo-code:
routine heaviestKPath( T, k )
// create 2D matrix with n rows and k columns with each element = -∞
// we make it size k+1 because the 0th column must be all 0s for a later
// function to work properly and simplicity in our algorithm
matrix = new array[ T.getVertexCount() ][ k + 1 ] (-∞);
// set all elements in the first column of this matrix = 0
matrix[ n ][ 0 ] = 0;
// fill our matrix by traversing the tree
traverseToFillMatrix( T.root, k );
// consider a path that would arc over a node
globalMaxWeight = -∞;
findArcs( T.root, k );
return globalMaxWeight
end routine
// node = the current node; k = the path length; node.lc = node’s left child;
// node.rc = node’s right child; node.idx = node’s index (row) in the matrix;
// node.lc.wt/node.rc.wt = weight of the edge to left/right child;
routine traverseToFillMatrix( node, k )
if (node == null) return;
traverseToFillMatrix(node.lc, k ); // recurse left
traverseToFillMatrix(node.rc, k ); // recurse right
// in the case that a left/right child doesn’t exist, or both,
// let’s assume the code is smart enough to handle these cases
matrix[ node.idx ][ 1 ] = max( node.lc.wt, node.rc.wt );
for i = 2 to k {
// max returns the heavier of the 2 paths
matrix[node.idx][i] = max( matrix[node.lc.idx][i-1] + node.lc.wt,
matrix[node.rc.idx][i-1] + node.rc.wt);
}
end routine
// node = the current node, k = the path length
routine findArcs( node, k )
if (node == null) return;
nodeMax = matrix[node.idx][k];
longPath = path[node.idx][k];
i = 1;
j = k-1;
while ( i+j == k AND i < k ) {
left = node.lc.wt + matrix[node.lc.idx][i-1];
right = node.rc.wt + matrix[node.rc.idx][j-1];
if ( left + right > nodeMax ) {
nodeMax = left + right;
}
i++; j--;
}
// if this node’s max weight is larger than the global max weight, update
if ( globalMaxWeight < nodeMax ) {
globalMaxWeight = nodeMax;
}
findArcs( node.lc, k ); // recurse left
findArcs( node.rc, k ); // recurse right
end routine
Let me know what you think. Feedback is welcome.
I think have come up with two naive algorithms that find the heaviest length-constrained path in a weighted Binary Tree. Firstly, the description of the algorithm is as follows: given an n-vertex Binary Tree with weighted edges and some value k, find the heaviest path of length k.
For both algorithms, I'll need a reference to all vertices so I'll just do a simple traversal of the Tree to have a reference to all vertices, with each vertex having a reference to its left, right, and parent nodes in the tree.
Algorithm 1
For this algorithm, I'm basically planning on running DFS from each node in the Tree, with consideration to the fixed path length. In addition, since the path I'm looking for has the potential of going from left subtree to root to right subtree, I will have to consider 3 choices at each node. But this will result in a O(n*3^k) algorithm and I don't like that.
Algorithm 2
I'm essentially thinking about using a modified version of Dijkstra's Algorithm in order to consider a fixed path length. Since I'm looking for heaviest and Dijkstra's Algorithm finds the lightest, I'm planning on negating all edge weights before starting the traversal. Actually... this doesn't make sense since I'd have to run Dijkstra's on each node and that doesn't seem very efficient much better than the above algorithm.
So I guess my main questions are several. Firstly, do the algorithms I've described above solve the problem at hand? I'm not totally certain the Dijkstra's version will work as Dijkstra's is meant for positive edge values.
Now, I am sure there exist more clever/efficient algorithms for this... what is a better algorithm? I've read about "Using spine decompositions to efficiently solve the length-constrained heaviest path problem for trees" but that is really complicated and I don't understand it at all. Are there other algorithms that tackle this problem, maybe not as efficiently as spine decomposition but easier to understand?
You could use a DFS downwards from each node that stops after k edges to search for paths, but notice that this will do 2^k work at each node for a total of O(n*2^k) work, since the number of paths doubles at each level you go down from the starting node.
As DasBoot says in a comment, there is no advantage to using Dijkstra's algorithm here since it's cleverness amounts to choosing the shortest (or longest) way to get between 2 points when multiple routes are possible. With a tree there is always exactly 1 way.
I have a dynamic programming algorithm in mind that will require O(nk) time. Here are some hints:
If you choose some leaf vertex to be the root r and direct all other vertices downwards, away from the root, notice that every path in this directed tree has a highest node -- that is, a unique node that is nearest to r.
You can calculate the heaviest length-k path overall by going through each node v and calculating the heaviest length-k path whose highest node is v, finally taking the maximum over all nodes.
A length-k path whose highest node is v must have a length-i path descending towards one child and a length-(k-i) path descending towards the other.
That should be enough to get you thinking in the right direction; let me know if you need further help.
Here's my solution. Feedback is welcome.
Lets treat the binary tree as a directed graph, with edges going from parent to children. Lets define two concepts for each vertex v:
a) an arc: which is a directed path, that is, it starts from vertex v, and all vertices in the path are children of the starting vertex v.
b) a child-path: which is a directed or non-directed path containing v, that is, it could start anywhere, end anywhere, and go from child of v to v, and then, say to its other child. The set of arcs is a subset of the set of child-paths.
We also define a function HeaviestArc(v,j), which gives, for a vertex j, the heaviest arc, on the left or right side, of length j, starting at v. We also define LeftHeaviest(v,j), and RightHeaviest(v,j) as the heaviest left and right arcs of length j respectively.
Given this, we can define the following recurrences for each vertex v, based on its children:
LeftHeaviest(v,j) = weight(LeftEdge(v)) + HeaviestArc(LeftChild(v)),j-1);
RightHeaviest(v,j) = weight(RightEdge(v)) + HeaviestArc(RightChild(v)),j-1);
HeaviestArc(v,j) = max(LeftHeaviest(v,j),RightHeaviest(v,j));
Here j here goes from 1 to k, and HeaviestArc(v,0)=LeftHeaviest(v,0),RightHeaviest(v,0)=0 for all. For leaf nodes, HeaviestArc(v,0) = 0, and HeaviestArc(v,j)=-inf for all other j (I need to think about corner cases more thoroughly).
And then HeaviestChildPath(v), the heaviest child-path containing v, can be calculated as:
HeaviestChildPath(v) = max{ for j = 0 to k LeftHeaviest(j) + RightHeaviest(k-j)}
The heaviest path should be the heaviest of all child paths.
The estimated runtime of the algorithm should be order O(kn).
def traverse(node, running_weight, level):
if level == 0:
if max_weight < running_weight:
max_weight = running_weight
return
traverse(node->left,running_weight+node.weight,level-1)
traverse(node->right,running_weight+node.weight,level-1)
traverse(node->parent,running_weight+node.weight,level-1)
max_weight = 0
for node in tree:
traverse(node,0,N)

Resources