Find a maximum tree subgraph with given number of edges that is a subgraph of a tree - algorithm

So a problem is as follows: you are given a graph which is a tree and the number of edges that you can use. Starting at v1, you choose the edges that go out of any of the verticies that you have already visited.
An example:
In this example the optimal approach is:
for k==1 AC -> 5
for k==2 AB BH -> 11
for k==3 AC AB BH -> 16
At first i though this is a problem to find the maximum path of length k starting from A, which would be trivial, but the point is you can always choose to go a different way, so that approach did not work.
What i though of so far:
Cut the tree at k, and brute force all the possibilites.
Calculate the cost of going to an edge for all edges.
The cost would include the sum of all edges before the edge we are trying to go to divided by the amount of edges you need to add in order to get to that edge.
From there pick the maximum, for all edges, update the cost, and do it again until you have reached k.
The second approach seems good, but it reminds me a bit of the knapsack problem.
So my question is: is there a better approach for this? Is this problem NP?
EDIT: A counter example for the trimming answer:

This code illustrates a memoisation approach based on the subproblem of computing the max weight from a tree rooted at a certain node.
I think the complexity will be O(kE) where E is the number of edges in the graph (E=n-1 for a tree).
edges={}
edges['A']=('B',1),('C',5)
edges['B']=('G',3),('H',10)
edges['C']=('D',2),('E',1),('F',3)
cache={}
def max_weight_subgraph(node,k,used=0):
"""Compute the max weight from a subgraph rooted at node.
Can use up to k edges.
Not allowed to use the first used connections from the node."""
if k==0:
return 0
key = node,k,used
if key in cache:
return cache[key]
if node not in edges:
return 0
E=edges[node]
best=0
if used<len(E):
child,weight = E[used]
# Choose the amount r of edges to get from the subgraph at child
for r in xrange(k):
# We have k-1-r edges remaining to be used by the rest of the children
best=max(best,weight+
max_weight_subgraph(node,k-1-r,used+1)+
max_weight_subgraph(child,r,0))
# Also consider not using this child at all
best=max(best,max_weight_subgraph(node,k,used+1))
cache[key]=best
return best
for k in range(1,4):
print k,max_weight_subgraph('A',k)

Related

How can I know all possible ways that the edges are connected if I know the toposort in a graph?

How can I know all possible ways that the edges are connected if I know the topological sort?
Here is the original problem:
Now little C has topologically sorted a simple (no heavy edges) directed acyclic graph, but accidentally lost the original. Except for topological sequences, little C only remembers that the original graph had the number of edges k, and that there is one vertex u in the graph that can reach all the other vertices. He wants to know how many simple directed acyclic graphs there are that satisfy the above requirements. Since the answer may be large, you only need to output the remainder of the answer module m.
I have just learned the topological sort. I wonder how I can use it in an upside down way? I know the final toposorted way as (1 2 3 4) and there is one vertex that connects all other vertexes, and there are 4 edges in all, but I need the number of all possible ways that edges are linked.
I think this problem has something to deal with permutation number,and the specific u has to be the first in the toposorted list.
NOTICE the max of m can be up to 200'000,so definitely you can not brute force this problem!!!
Let the topological order be u = 1, 2, …, n. Since 1 can reach all other
vertices, the topological order begins with 1. Each node v > 1, being
reachable from u, must have arcs from one or more nodes < v. These
choices are linked only by the constraint on the number of arcs.
We end up computing Count[v][m] (modulo whatever the modulus is) as
the number of reconstructions on 1, 2, …, v with exactly m arcs. The
answer is Count[n][k].
Count[1][0] = 1 if m == 0 else 0
for v > 1, Count[v][m] = sum for j = 1 to min(m, v-1) of (v-1 choose j)*Count[v-1][m-j]

Choosing k vertices from binary tree vertices set such that sum of cost edges in this new k vertices subset is minimum

Given a binary tree T with a weight function on its edge set w : E -> Z
(Note the weight can be negative too) and a positive integer k. For
a subset T' of V (T), cost(T') is defined as the sum of the weights of
edges (u, v) such that u, v ∈ T'
.Give an algorithm to find a subset T'
of exactly k vertices that minimizes cost(T').
How to solve this problem using dynamic programming?
It is usually easier to solve dynamic programming problems top down. They are often more efficient if solved bottom up. But I'll just get you going on the easier version.
Fill out this recursive function:
def min_cost(root, count_included, include_root):
# root is the root of the subtree
# count_included is how many nodes in the subtree to include in T'
# include_root is whether root will be in T'.
#
# It will return the minimum cost, or math.inf if no solution exists
...
And with that, your answer will be:
min_cost(root_of_tree, k, True) + min_cost(root_of_tree, k, False)
This is slow, so memoize for the top down.
I will leave the bottom up as a more difficult exercise.

Algorithm for finding spanning tree with minimum range in a given graph

Given a weighted undirected graph G(v,e) with weights w(e), find the set of edges such that each pair of vertices (u,v)∈G are connected (in short, spanning tree) and the range of weights of selected edges is minimum (or the difference between the minimum weight and the maximum weight is minimum).
I tried greedy approach in which sorted the edges with respect to weights and then selected two edges with minimum weight difference between the consecutive edges (g[index = current_left],g[index+1 = current_right]) in the sorted array, subsequently I moved left or right depending on the minimum difference between the (current_left,current_left-j) or (current_right,current_right+j) where j is incremented till we find an edge with at least one non-visited vertex.
For example:
Here the minimum range that we can get is by selecting edges with weight {2,3,5} and the range is 3.
Please point a test case where the suggested algorithm fails and suggest an algorithm for finding such spanning tree.
Edit:
Expected time complexity is O(|E|log|E|) where |E| is number of edges.
You should be able to do it in O(E * (cost of MST computation)):
T = no tree
for all edge weights w_fix sorted in ascending order:
for all edges e:
if w(e) >= w_fix:
set w'(e) = w(e) - w_fix
else:
set w'(e) = infinity
find MST T' according to w'
if T == no tree or max edge weight(T) > max edge weight(T'):
set T := T'
print T
The idea is that some edge weight has to be the minimum edge weight among the edges in an optimal spanning tree; so fix a minimum edge weight and find an MST that only contains edges heavier than that. Since all MSTs are also minimum bottleneck spanning trees, this will work.
Here's an improvement that is optimal up to a log-square factor; the basic idea remains the same.
sort edge array E[] by increasing weights
low := high := 0
opt_low := opt_high := 0
opt := infinity
connected := false
while (high < E.length - 1) or (connected):
if not connected:
high = high + 1
else:
low = low + 1
update(connected)
if connected:
if E[high].weight - E[low].weight < opt:
opt = E[high].weight - E[low].weight
opt_low = low
opt_high = high
print(opt, opt_low, opt_high)
The idea is to keep a sliding window over the edges and use connectivity to maintain the window. To maintain connectivity information, you would use special data structures. There's a number of them that allow for polylogarithmic time costs to maintain connectivity information for both deleting and adding edges, and you can find information on those data structures in these MIT 6.851 lecture notes.
The algorithm described by G Bach infact works correctly and has a run time of O(m*m) where m is the number of edges(considering the computation of mst takes O(m) time). This was a question asked in codeforces edu section.

Divide a graph into two sets

The Question is from Code jam.
Question:
Is there any way to divide the nodes of a graph into two group such that any two nodes which can't remain in the same group should be in different group.
Is there any standard algorithm for this?
How should I tackle this problem when each group should have equal element.
First, the feasibility problem (is there such set/ doesn't exist such set) is 2-coloring problem, where:
G = (V,E)
V = { all nodes }
E = { (u,v) | u and v are "troubling each other" }
This problem is solved by checking if the graph is bi-partite, and can be done using BFS.
How to tackle the problem when each group should have equal element.
first, let's assume the graph is bi-partite, so there is some solution.
Split the graph into set of connected components: (S1,S2,S3,...,Sk).
Each connected component is actually a subgraph (Si = Li,Ri) - where Li,Ri are the two sides of the bipartite graph (there is only one such splitting in each connected component, if ignoring the order of Li and Ri).
Create a new array:
arr[i] = |Li| - |Ri|
where |X| is the cardinality of X (number of elements in the set)
Now, solving this problem is same as solving the partition problem, which can be done in pseudo-polynomial time (which is polynomial in the number of nodes).
The solution to partition problem splits each arr[i] to be in A or in B, such that sum{A} is closest as possible to sum{B}. If arr[i] is in A, in your solution, color Li with "1", and Ri with "2". Otherwise - do the opposite.
Solution will be O(k*n+m), where k is number of connected components, n is number of nodes in the graph, and m is number of edges in the graph.
You build a graph from the given nodes (using a hash-table to map names to nodes) and then you use BFS or DFS to traverse the graph and determine if its bipartite (that is, divisibe into two disjoint sets such that a node in one set is only in "trouble" with nodes in the other set, but not with any node in its own set). This is done by assigning a boolean value to each node as its visited by the BFS/DFS and then checking if any of its visited neighbors has the same value, which means the graph is not bipartite (not divisible into two groups).

Graph travelling algorithm

I've got an interesting graph-theory problem. I am given a tree T with n nodes and a set of edges. T is, of course, undirected. Each edge has weight that indicates how many times (at least) it has to be visited. We are strolling from node to node using edges and the task is to find minimal number of needed steps to satisfy above conditions. I can start from any node.
For example, this tree (edge weight in parentheses):
1 - 2 (1)
2 - 3 (1)
3 - 4 (2)
4 - 5 (1)
4 - 6 (1)
we need 8 steps to walk this tree. That are for example: 1->2->3->4->3->4->5->4->6
I don't know how to approach this algorithm. Is it possible to find this optimal tour or can we find this minimal number not directly?
Add extra edges to your graph corresponding to the weight of each edge. (i.e. if a->b has weight 3, then your graph should include 3 undirected edges connections between a and b).
Then what you are trying to find is called an Eulerian trail on this graph.
A Eulerian trail can be closed (if start==end) or open (if start!=end).
Closed trails exist if all nodes have even degree.
Open trails exist if all nodes except 2 have even degree.
Paths can be found using Fleury’s Algorithm (faster linear algorithms also exist if this is too slow).
If your graph does not satisfy the requirements for an Eulerian trail, then simply add the smallest number of extra edges until it does.
One way of doing this is to perform a depth first search over the tree and keep track of the minimum number of edges that you can add to each subtree in order that it has 0,1, or 2 vertices of odd degree. This should take time linear in the number of nodes in the tree.
EXAMPLE CODE
This Python code computes the shortest number of steps for a graph.
(To construct the graph you should consider it as a rooted graph and add edges for each edge going away from the root)
from collections import defaultdict
D=defaultdict(list)
D[1].append((2,1))
D[2].append((3,1))
D[3].append((4,2))
D[4].append((5,1))
D[4].append((6,1))
BIGNUM=100000
class Memoize:
def __init__(self, fn):
self.fn = fn
self.memo = {}
def __call__(self, *args):
if not self.memo.has_key(args):
self.memo[args] = self.fn(*args)
return self.memo[args]
#Memoize
def min_odd(node,num_odd,odd,k):
"""Return minimum cost for num_odd (<=2) odd vertices in subtree centred at node, and using only children >=k
odd is 1 if we have an odd number of edges into this node from already considered edges."""
edges=D[node]
if k==len(edges):
# No more children to consider, and no choices to make
if odd:
return 0 if num_odd==1 else BIGNUM
return 0 if num_odd==0 else BIGNUM
# We decide whether to add another edge, and how many of the odd vertices to have coming from the subtree
dest,w0 = edges[k]
best = BIGNUM
for extra in [0,1]:
w = w0+extra
for sub_odd in range(num_odd+1):
best = min(best, w + min_odd(dest,sub_odd,w&1,0) + min_odd(node,num_odd-sub_odd,(odd+w)&1,k+1) )
return best
root = 1
print min( min_odd(root,2,0,0),min_odd(root,0,0,0) )

Resources