Algorithm to 'trim' a graph - algorithm

I am trying to create an algorithm to calculate the total resistance for a given an undirected graph with weighted edges. The algorithm will also be given a starting node and an ending node, which will represent the terminals connected to the power supply. For example, the graph on the top with starting node 1 and ending at node 6 will represent this circuit
(3)
|
|6
3 |
(2)------(4)
| |
|5 |1
| |
| 3 | 1
(1)------(5)------(6)
As you would realize, the 6 ohm resistor doesn't really matter in this context as current wouldn't flow through it if a voltage was applied between nodes 1 and 6. So, I figured that I should first of all 'trim' this graph. Here is the explanation of this process:
Trimming a graph is basically cutting off the parts of the graph which cannot be contained in a path between the starting node and the ending node which passes over any node at most once.
4 4
| /|
| / |
2--3 2--3 2--3
| | | | | |
| | | | | |
1--5--6 1--5--6 1--4--5
(1) (2) (3)
For example, in graph (1), node 4 should be trimmed because in any path between 1 and 6, visiting node 4 means visiting node 3 at least twice as there is no path from node 4 which doesn't visit node 3 again. If this graph is trimmed, it will become graph (3). However, if graph (2) is trimmed, it won't change because all nodes can be visited on a path from 1 to 6, including node 4.
So, how can I devise an algorithm that trims a graph with given starting and ending nodes?
EDIT: So, I have learned about the maxflow / mincut problem, and it seems like this could be used for the solution of this problem. I haven't tried it yet, but I will post another edit if I can manage to do it using flows.

Find the tree of Biconnected components.
Any node that is not on the path from s to t in the tree (or part of the component that is on the path) can be removed.
The time complexity is linear.
Biconnected component: https://en.wikipedia.org/wiki/Biconnected_component

Just remove all nodes with only one edge (not counting for the two ending nodes).
But this does not account for the nodes "beyond" the ending nodes. If in your original graph we want to calculate the resistance between nodes 5 and 6 then we do not need any other node (nodes 1, 2, 3 and 4 are all irrelevant).
To remove really all nodes that are irrelevant you have to find all different paths between the two ending nodes, and remove all nodes that are not part of any of those paths.

This can be a possible solution for this:
If starting from a node (say v) if we can reach both the source and terminal nodes with no vertices in common then that node has to be considered for the calculation of the total resistance.
By this I mean, suppose one of the path from v to source is (v, a1, a2, a3, a4, ..., source)
And the path from v to terminal be (v, b1, b2, b3, ..., terminal)
Then if the intersection of these gives zero elements, then the node v can not be trimmed. Otherwise it can be left out.
So we can have the following two solutions for this:
1. Do a depth-first search from each vertex and check if the paths have some common vertex or not.
Find all the bridges in the graph. You can look for it here: https://en.wikipedia.org/wiki/Bridge_(graph_theory)
The way to find all the bridges in a graph is given here: https://www.geeksforgeeks.org/bridge-in-a-graph/
If after removing a bridge-edge, the source and terminal vertices are in the same connected component then all the nodes on the other side of connected component can be trimmed from the graph.
For example: In the graph (1), there is only one bridge 3-4.
If we remove that we get two connected components (1,2,3,5,6) and (4). We can see that both 1 and 6 are in the same connected component, hence all other connected component nodes (here only node numbered 4) can be trimmed.

Related

Computing level of nodes in a graph

I want to compute the level of each node in a directed graph. I'm currently applying a depth-first search algorithm on vertices that have no incoming edges. Considering the graph below, for instance:
The expected result is:
Vertex | Level
1 | 0
2 | 1
3 | 2
4 | 1
5 | 3
6 | 4
In this particular case, if we start by applying DFS on 4, then all results for vertices 4, 3, 5 and 6 are going to be wrong, since 1 has level 0. I've tried to always consider the greatest result for each one of the nodes, so in this case the results for 3, 5, and 6 are replaced when applying DFS on 1. It works, but I can't find a way to correctly compute the level of vertex 4.
I'm working only with directed acyclic graphs.
I'm not including any code here because it is a pretty straightforward DFS implementation and I'm not struggling implementation-wise.
Any hint would be much appreciated.
You can compute the levels starting from each vertex without having an incoming edge. Then you can store the maximum value for each vertex until the end. For eg :- Vertex 3 will have values 1 and 2 when traversed from starting points vertex 1 and vertex 4 respectively. At last, you can update the vertices not having the incoming edge(number on child -1). If there's a situation where there multiple children of such a vertex, then you might want to select the child with maximum number on it for replacement and then run the algorithm from that vertex again to see if changes the numbers assigned to any of the other children.

How to find 4 non intersecting spanning trees in 2D Torus

In my implementation I need to find 4 non intersecting spanning trees in a 2D torus. Assuming all the links are bidirectional. and Bidirectional links are not intersecting.
Ex: my 2D torus is of 3 * 3
| | |
--0-1-2--
| | |
--3-4-5--
| | |
--6-7-8--
| | |
So, each link here is actually representing a bidirectional link for example there are two edges between 0 and 3. one from 0 towards 3 and one from 3 towards 0.
In output I should get 4 non intersecting spanning trees.
Although I have thought of some algorithm but it fails somehow.
ALgorithm:
I have the torus represented in the form of adjacency matrix. And a link between 0 and 3 are represented by 1 in adjacency matrix at position AM[0][3] and AM[3][0]
Node consist of (node_number, parent,weight)
Intially I maintain a priorList in which all nodes are set to their (node_number, -1, INT_MAX) but root of spanning tree which is set to (node_number, -1, 0)
Extract node from priorList with minimum weight, such that its parent does not have already a child. (In first iteration it would always be root). This I do by checking in the set of already extracted nodes in MST.
If found then update all its neighbours other than the nodes already extracted from priorList.
here by updating I mean update their parents, if already discovered.
Now add the extracted node in 1st step into the MST.
Go to step 1 until priorList is not empty.
It will give 1 MST but will get stuck while getting the 2nd MST from the same Adjacency matrix which was left as output while calculation of 1st MST(By which I mean if I had already used some edges in the 1st MST then I would have removed that edges from the Matrix).
Remember all 4 spanning trees should start from the same given root, and try if I can somehow use variant of Prim's algorithm(http://en.wikipedia.org/wiki/Prim%27s_algorithm).
I don't know any other algorithm as of now, but lets see if someone can help.

Finding length of shortest cycle in undirected graph

I tried the following :
1) DFS, keeping track of level of each vertex in my DFS tree
2) Each time a back edge (x,y) is seen, I calculate cycle length = level[x] - level[y] + 1, and save it if it is smaller than the shortest
Can someone tell a counter example for which this approach is wrong ?
What could be a better way to find shortest cycle in undirected graphs ?
Thanks.
Why DFS won't work
You cannot use DFS to find a shortest circle. We can easily create a counter example, where DFS leads finds only the longest circle. Lets have a look at the following graph:
As you can see we have nine nodes. If we start at the leftmost node A, the following DFS level could be possible:
We have two back edges while iterating:
(B , A), therefore we found a circle with length 8
(D , A), therefore we found a circle with length 8
However, the shortest circle has length 5. It's shown in blue in the next picture, whereas one of the previously found circles is shown in red:
You didn't see the blue circle because your DFS path doesn't contain it.
Dagupa et al also mention this behaviour in their book:
But it also means that DFS can end up taking a long and convoluted route to a vertex that is actually very close by.
Why BFS won't work
Well, that's not entirely true, one can use BFS (see next subsection), but you cannot use your formula. Take the following graph:
No fancy picture for this graph yet.
Every "o" is a node.
o---o
| |
+-------o---o-------+
| |
o----o----o----o----o
Lets see what levels are possible in BFS. If I start at the node in the middle, I get the following levels:
5~~~5 ~~~ are back-edges
| |
+-------4~~~4-------+
| |
3----2----1----2----3
And if I start at the left node, I get the following levels:
3~~~4
| |
+-------2---3-------+
| |
1----2----3----4~~~~4
Therefore, you cannot use your level formula.
Solution
Although not efficient, using an all-pair shortest path algorithm and checking the distance (i,i) for every node is a valid solution.
I think this is what you are looking for : https://web.archive.org/web/20170829175217/http://webcourse.cs.technion.ac.il/234247/Winter2003-2004/ho/WCFiles/Girth.pdf
You make a BFS from each node, thus you have complexity O(V*E)
Let's say we've the graph with following edges,
1<->4,
4<->2,
4<->3,
2<->3,
3<->1
Then cycle 1, 4, 2, 3, 1 could be traversed before 1, 4, 3, 1 and as we are considering DFS, no node will be visited twice. So if 1, 4, 2, 3, 1 is traversed first, no chance that 1, 4, 3, 1 or 4, 2, 3, 3 will be traversed at all. So with DFS it can NOT be assured that we will get the shortest cycle always.
Possible Improvement: A BFS tree should work fine as it goes level by level and for BFS tree distance from root to any node is fixed, no matter in which order nodes are picked. Runtime: O(V+E) while modified Floyd-Warshall's algorithm would run in O(V^3) in worst case.

What are the articulation points of this directed graph?

5 nodes in this directed graph.
Edges:
1 -> 2
2 -> 3
2 -> 4
4 -> 5
(Graphical image : http://i.imgur.com/hafBv.jpg )
Am I correct in thinking that the articulation points are node 2 and 4 ?
(If you remove node 2 or node 4, the graph becomes disconnected)
But the definition I've seen everywhere says something similar to:
a node u is an articulation point, if for every child v of u, there is no back edge from v to a node higher in the DFS tree than u.
How does this work for a directed graph? For example, Node 3 does not have a back edge to a node higher in the DFS tree than 2. Does this classify Node 3 as an articulation point? But its removal does not cause the graph to be broken into 2 or more pieces (That is my layman definition of an articulation node).
Disclaimer: My memory is vague.
Directed graphs have three kinds of connectedness.
"Strongly connected" if there is a path from every vertex to every other vertex,
"Connected" if there is a path between any two nodes, but not in both directions.
"Weakly connected" if the graph is only connected if the arcs are replaced with undirected arcs.
eg
1->2 , 2->3 , 3->1
Strongly connected, you can get from every node to every other node
1->2 , 2->3
You can't get from 3 to 1 but you can from 1 to 3 so it's connected
1->2 , 3->2
There is no way to get from 1 to 3 or from 3 to 1, so it's only weakly connected.
What nodes are articulation points depends on what kind of connectedness you are considering.
Your graph is only weakly connected since there's no way to get from 3 to 4 or from 4 to 3.
Which would mean that the only way it makes sense to talk about articulation points is if you treat the arcs as undirected. In which case 2 and 4 would be the articulation points, as you said.
Articulation point should always have children and parent. This is something that is missing from your definition and makes nodes 1 and 3 articulation points whilst they are not.
Also note that in your reasoning for node 3 you consider the node itself not its children. If you apply the definition carefully you will see that you should consider the children instead. In your case - empty set and, with the extended by me definition, 3 is no longer articulation point.
Node 3 does not have a back edge to a node higher in the DFS tree than 2
Node 3 doesnt have children, so it cannot be an articulation point (from def).
If we put this definition in the context of a directed tree, then the articular points are all the points except the root and the leaf node
but when we follow the method we used to solve the undirected graph we get the respected (num,low) values for nodes are node-1(1,1)
2 (2,2) ,node 3 (3,3), node 4(4,4).node 5(5,5).
so following the def of articulation point and finding the node with 2 children
and satisfying the rule (low(child)>=num(node))
we get only the node 2 so that is the articulation point .
but the theory can be applied because it is still a connected graph i.e where every node is reachable but when we are finding we had to take care of tree and back edges and the rest is same as that of undirected graph.
The definition of articulation is not as clear as in case of undirected graphs. However if we choose two particular nodes: source and sink and call any point that must occur on the path from source to sink articulation point, the definition is clear.
I call them unavoidable points and have got simple solution for finding them on my GitHub

Least number of rides

I'm trying to solve this problem using an algorithm for at least a week but to no avail. I have a set of roads (1,2,3,...) and for each road there can be at least 1 vehicle that can pass (A,B,C,...). My problem is how to get the least number of rides for one to take to reach one road to another. For example:
road | vehicle(s)
1 | A,B
2 | A,B,C
3 | C,D
4 | C,D
5 | D,E
The output should be:
from 1, ride A or B to 2
from 2, ride C to 4
from 4, ride D to 5
The policy here is to exhaust one ride as much as possible, but the output should have the least number of ride changes.
Example 2:
road | vehicle(s)
1 | A,B
2 | A,B,C
3 | C,D
4 | C,D
5 | A,E
6 | E,F
7 | F
8 | F,H
9 | F,G
10 | F,G
11 | F
12 | F,G
13 | G,H
14 | H
Output:
from 1, ride A to 5
from 5, ride E to 6
from 6, ride F to 8
from 8, ride H to 14
Please help me to write the algorithm for the problem. I need to solve this for my project. Thanks!
PS: If you need other examples or clarification, just tell me in the comments below.
One way to think about this problem is to model it as a graph search problem. For each of the different vehicles v, construct a graph Gv whose nodes are all of the roads in the network with arcs between the nodes that are connected by vehicle v. For example, in your first example, the graph GA would have five nodes, of which there is only a connection from node 1 to node 2, while the graph GC would have five nodes with edges from 2 to 3, 3 to 4, and 4 to 2.
Now, consider the final graph G constructed as follows. G is formed by taking all of the graphs Gv for all of the vehicles v (meaning that there are multiple copies of each node in the original graph), then adding edges between corresponding nodes in the different graphs if there are multiple different vehicles that all reach a road. For example, in the graph G for the original problem, you would have G contain subgraphs GA and GB, ..., GE. Since road 1 is serviced by both vehicles A and B, you would add an edge between the nodes for road 1 in the graphs GA and GB, and since road 2 is serviced by vehicles A, B, and C, there would be edges connecting all of the road 2 nodes for subgraphs GA, GB, and GC.
You are interested in minimizing the number of transfers you need to make, and so we'd like to set up some costs in this graph that measure that. In particular, we say that any edge contained completely in one of the subgraphs Gv has cost zero, since once you're on a vehicle of a given type you don't need to make any changes to move around the roads the vehicle services. However, we assign a cost of one to each of the edges linking the subgraphs for different vehicles, since following this sort of edge would mean that you're changing which vehicle you're using. If you now trace out any path in this graph, the total cost of that path is the number of vehicle changes you make.
To finalize the construction, we need to have some way of finding a cost from the starting road to the destination. To do this, we'll add two new nodes s and t to the graph representing the start and end of the journey. Node s will have cost-zero directed edges to the first road of each of the subgraphs, since when you start off the journey you can pick any of the vehicles as your first step. Similarly, every subgraph's node for the final road will have a zero-cost edge to t, since once you arrive at the destination road it doesn't matter what vehicle you're in.
In this setup, any path from s to t has a cost equal to the total number of transfers you need to make. Finding the shortest path in this graph from s to t therefore gives you both the route to take and the cost of that path. You can solve this using Dijkstra's algorithm, for example.
The runtime of this algorithm isn't stellar, but it's still polynomial time. Suppose that there are n roads and m different vehicles. The graph we create will have m different subgraphs in it, each of which is for one vehicle, and in the worst case these graphs have O(n2) edges in them. If we then link together all the corresponding nodes of these subgraphs where you can change lines, then in the worst case there will be O((mn)2) such edges, since there are m graphs of n nodes that all might be connected to one another. We thus have a graph with O(mn) nodes and O((mn)2) edges, so we can run Dijkstra's algorithm in O((mn)2 + mn log mn) time.
The main idea that I think is important to take away from this problem is that you can often solve problems about finding paths in graphs subject to certain constraints by creating a new graph formed out of multiple copies of the old graph and then coming up with a good edge-cost function for that graph.
Hope this helps!

Resources