Maximise number of edges to cut in connected graph - algorithm

This question is very similar to Leetcode's Critical Connections in a Network. Given an undirected graph, we want to find all bridges. An edge in an undirected connected graph is a bridge iff removing it disconnects the graph.
Variant
Instead of finding all bridges, I want to maximise the number of edges to remove so that the graph remains connected.
Example 1
Input: n = 5, edges = [[1, 2], [1, 3], [3, 4], [1, 4], [4, 5]]
Output: 1
Firstly, I can remove [3,4], [1,3], or [1,4]. Next, after removing either of the 3 edges, the remaining edges are all bridges. Hence, the maximum number of edges to remove so that the graph remains connected is 1.
Example 2
Input: n = 6, edges = [[1, 2], [1, 3], [2, 3], [2, 4], [2, 5], [4, 6], [5, 6]]
Output: 2

Well this is easy, if we have E edges and N nodes in a connected graph we can remove E-N+1 edges so that graph remains connected.
How to do this?:
Just do DFS/BFS to find any spanning tree of the graph, since spanning tree is connected we can just remove all other edges.

Related

Given facet information, how to efficiently check if a polyhedron composed of triangles is closed?

Let me clarify the definitions first. Consider a regular tetrahedron is composed of 4 vertices. Let's say the indices for these vertices are [0, 1, 2, 3]. Then, the definition of facet information is F = [[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 2, 3]]. A polyhedron composed of triangles is closed if any triangle facet is connected to 3 other triangles via edges. For example, a regular tetrahedron is closed.
Then, given facet information, how to efficiently check if a polyhedron composed of triangles is closed?
A naive solution to do this is as follows: making a graph that describes unordered connections between facets, then check that any node is connected to 3 other nodes. However, this naive method seems too slow for my application.
P.S. my implementation for comparing number of edges and vertices in python
def isClosed(F): # F is list of indices triplet
S = set()
for triplet in F:
for i, j in [[0, 1], [1, 2], [2, 0]]:
a, b = triplet[i], triplet[j]
key = (a, b) if a < b else (b, a)
S.add(key)
return len(F)*3 == len(S)*2

Is my postorder traversal of this graph correct?

I am trying to implement an algorithm that requires a post-order traversal. Here is my graph (taken from here, pg. 8):
When I try to do a postorder traversal of this, the order I get is:
[3, 2, 1, 5, 4, 6]
The problem with this order is that the algorithm won't work in this order. This is the code I am using to get it (pseudocode):
function PostOrder(root, out_list) {
root.visited = true
for child in root.Children {
if not child.visited {
PostOrder(child, out_list)
}
}
out_list.append(root)
}
Is the postorder correct?
Yes, the post order traversal of your algorithm is correct. The expected output is indeed as you provided it.
Your confusion may come from the fact that the graph is not a binary tree, and not even a tree. It is a directed graph.
In general postorder means that you first perform a postorder traversal on the node behind the first outgoing edge, then on the node behind its next outgoing edge, ...etc, and only after all outgoing edges have been traversed, the node itself is output.
Since at node 1 you are not at the end yet, and still can go to 2, and from there to 3, you need to follow those edges before outputting anything. And only then backtrack.
For reference, here is your algorithm implemented in python:
def postorder(root, out_list, children, visited):
visited[root] = True
for child in children[root]:
if not visited[child]:
postorder(child, out_list, children, visited)
out_list.append(root)
children = [
[], # dummy for node 0
[2], # 1
[1,3], # 2
[2], # 3
[2,3], # 4
[1], # 5
[5,4] # 6
]
nodes = []
postorder(6, nodes, children, [False] * len(children))
print(nodes) # [3, 2, 1, 5, 4, 6]
I think you got confused with the postorder traversal of binary trees.
Postorder traversal in graph is different.
Post Ordering in Graphs – If we list the vertices in the order in which they are last visited by DFS traversal then the ordering is called PostOrder.
Assuming your root is node is 6, the order mentioned gives the correct answer.
Checkout the following example on how the post order traversal list is generated:
Pass 1:
List:[]
6 -> 5 -> 1 -> 2 -> 3 (Now Node 3 has no adjacent nodes which are unvisited)
List: [3]
Pass 2:
6 -> 5 -> 1 -> 2
Node 2 has has no adjacent nodes which are unvisited.
List: [3, 2]
Pass 3:
6 -> 5 -> 1
Node 1 has has no adjacent nodes which are unvisited.
List: [3, 2, 1]
Pass 4:
6 -> 5
Node 5 has has no adjacent nodes which are unvisited.
List: [3, 2, 1, 5]
Pass 5:
6 -> 4
Node 4 has has no adjacent nodes which are unvisited.
List: [3, 2, 1, 5, 4]
Pass 6:
Node 6 has has no adjacent nodes which are unvisited.
List: [3, 2, 1, 5, 4, 6]
Important Notes:
As we are using DFS, there can be multiple paths possible depending upon the order of the nodes in the adjacency list.
Possible are the correct orders:
[3, 2, 1, 5, 4, 6]
[1, 3, 2, 4, 5, 6]
[3, 1, 2, 4, 5, 6]
[1, 2, 3, 4, 5, 6]

Given a tree represented in the form of nested lists, how do I traverse it breadth first?

Suppose I have the a tree given in the nested list representation, how do I traverse it breadth first? For example, if I'm given
[1, [2, [3, [4, [3, 5]]]], [3, [4, 5, 2]]]
The output would be
[1,2,3,3,4,4,5,2,3,5]
Also, given a flattened representation of the depth-first order like [1,2,3,4,3,5,3,4,5,2], how do I find the indices of the breadth-first order?
Thanks in advance for any help.
Here's the code in Python:
queue = [1, [2, [3, [4, [3, 5]]]], [3, [4, 5, 2]]]
while queue:
firstItem = queue.pop(0)
if type(firstItem) is list:
for item in firstItem:
queue.append(item)
else:
print('Traversed %d' % (firstItem))
The output is:
Traversed 1
Traversed 2
Traversed 3
Traversed 3
Traversed 4
Traversed 5
Traversed 2
Traversed 4
Traversed 3
Traversed 5
After studying my output and what you specified the output should be in your question, I think my output is more correct. More specifically, the left most 3 in the input list and [4, 5, 2] at the end of the input list are on the same "level", and thus should be traversed 3, 4, 5, 2, as shown from the 4th line to the 7th line of my output.
As for your second question, I think you should ask a separate question because it really is a completely different question.

Place Intervals to Maximize Number of Adjacency

My problem:
I have n "items" to place on an integer axis. Each item contains several choices of placement, represented as closed intervals of integers. These intervals can have some overlapping elements. The goal is to find a non-overlapping placement (if any) of the n items on the int axis with maximal number of interval adjacency.
More details with the terms used above:
1) Overlapping: interval [1, 4] and [3, 6] have two overlapping elements {3} and {4}; interval [2, 5] and [6, 10] do not overlap.
2) Interval adjacency: interval [a, b] and [b+1, c] are called adjacent. The number of interval adjacency for this example is 1. The maximal possible number of interval adjacency for n items is n-1, which occurs when the placement makes n intervals pair-wisely adjacent.
Example:
There are 3 items; their placement choices are listed here
item1 has 2 choices: [1, 4], [2, 5]
item2 has 3 choices: [5, 8], [9, 11], [16, 18]
item3 has 2 choices: [3, 5], [13, 15]
One feasible placement is
[1, 4](item1), [5, 8](item2), [13, 15](item3)
Another two feasible placement are
[1, 4](item1), [16, 18](item2), [13, 15](item3); and
[2, 5](item1), [16, 18](item2), [13, 15](item3).
All these three placement in this example are optimal. The number of interval adjacency is 1.
My question:
Is there a better way than enumeration of all possibilities?
I can only think of that if an interval choice of an item overlaps with all the choices of another item, then this choice can be excluded. Any ideas are welcome:)

Giving an example of a cycle in a directed graph

I want an algorithm that gives one instance of a cycle in a directed graph if there is any. Can anyone show me a direction? In pseudo-code, or preferably, in Ruby?
I previously asked a similar question, and following the suggestions there, I implemented Kahn's algorithm in Ruby that detects if a graph has a cycle, but I want not only whether it has a cycle, but also one possible instance of such cycle.
example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
Kahn's algorithm
def cyclic? graph
## The set of edges that have not been examined
graph = graph.dup
n, m = graph.transpose
## The set of nodes that are the supremum in the graph
sup = (n - m).uniq
while sup_old = sup.pop do
sup_old = graph.select{|n, _| n == sup_old}
graph -= sup_old
sup_old.each {|_, ssup| sup.push(ssup) unless graph.any?{|_, n| n == ssup}}
end
!graph.empty?
end
The above algorithm tells whether a graph has a cycle:
cyclic?(example_graph) #=> true
but I want not only that but an example of a cycle like this:
#=> [[2, 3], [3, 6], [6, 2]]
If I were to output the variable graph in the above code at the end of examination, it will give:
#=> [[2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
which includes the cycle I want, but it also includes extra edges that are irrelevant to the cycle.
I asked the same question in the math stackexchange site, and got an answer. It turned out that Tarjan's algorithm is good for solving this problem. I implemented it in Ruby as follows:
module DirectedGraph; module_function
## Tarjan's algorithm
def strongly_connected_components graph
#index, #stack, #indice, #lowlink, #scc = 0, [], {}, {}, []
#graph = graph
#graph.flatten(1).uniq.each{|v| strong_connect(v) unless #indice[v]}
#scc
end
def strong_connect v
#indice[v] = #index
#lowlink[v] = #index
#index += 1
#stack.push(v)
#graph.each do |vv, w|
next unless vv == v
if !#indice[w]
strong_connect(w)
#lowlink[v] = [#lowlink[v], #lowlink[w]].min
elsif #stack.include?(w)
#lowlink[v] = [#lowlink[v], #indice[w]].min
end
end
if #lowlink[v] == #indice[v]
i = #stack.index(v)
#scc.push(#stack[i..-1])
#stack = #stack[0...i]
end
end
end
So if I apply it to the example above, I get a list of strongly connected components of the graph:
example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
DirectedGraph.strongly_connected_components(example_graph)
#=> [[4], [5], [2, 3, 6], [1]]
By selecting those components that are longer than one, I get the cycles:
DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
#=> [[2, 3, 6]]
And further if I select from the graph the edges whose both vertices are included in the components, I get the crucial edges that constitute the cycles:
DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
.map{|a| example_graph.select{|v, w| a.include?(v) and a.include?(w)}}
#=> [[[2, 3], [3, 6], [6, 2]]]
Depth first search, where you keep track of the visited vertices and the parent will give you the cycle. If you see an edge to a previously visited vertex then you have detected a cycle between your parent, yourself, and that vertex. A slight problem you may encounter is, if it is a cycle of length > 3, you'll only be able to tell the three vertices involved and will have to do some investigation into finding the rest of the vertices in the cycle.
For the investigation, you can start a breadth first search 'up' the tree starting from the parent and looking for the visited vertex, you should be able to find the whole cycle by doing that.

Resources