Minimum Hop Count in Directed Graph based on Conditional Statement - algorithm

A directed graph G is given with Vertices V and Edges E, representing train stations and unidirectional train routes respectively.
Trains of different train numbers move in between pairs of Vertices in a single direction.
Vertices of G are connected with one another through trains with allotted train numbers.
A hop is defined when a passenger needs to shift trains while moving through the graph. The passenger needs to shift trains only if the train-number changes.
Given two Vertices V1 and V2, how would one go about calculating the minimum number of hops needed to reach V2 starting from V1?
In the above example, the minimum number of hops between Vertices 0 and 3 is 1.
There are two paths from 0 to 3, these are
0 -> 1 -> 2 -> 7-> 3
Hop Count 4
Hop Count is 4 as the passenger has to shift from Train A to B then C and B again.
and
0 -> 5 -> 6 -> 8 -> 7 -> 3
Hop Count 1
Hop Count is 1 as the passenger needs only one train route, B to get from Vertices 0 to 3
Thus the minimum hop count is 1.
Input Examples
Input Graph Creation
Input To be solved
Output Example
Output - Solved with Hop Counts
0 in the Hop Count column implies that the destination can't be reached

Assuming number of different trainIDs is relatively small (like 4 in your example), then I suggest using layered graph approach.
Let number of vertices be N, number of edges M, and number of different trainIDs K.
Let's divide our graph to K graphs. (graphA, graphB, ...)
graphA contains only edges labeled with A, and so on.
Weight of each edge in each of the graphs is 0.
Now create edges between these graphs.
Edge between graphs is representing a 'hop'
grapha[i] connects to graphB[i], graphC[i], ...
Each of these edges has weight 1.
Now for every graph run Dijkstra's shortest path algorithm from V1 in that graph, and read results from V2 in all graphs, take minimal value.
This way minimum of results for running dijkstra's for every graph will be your minimum number of hops.
Memory complexity is O(K*(N+M))
And time complexity is O(K*(((2^K)*N+M)*log(KV)))
(2^K)*N comes from fact that for every 1<=i<=N, vertices graphA[i],graphB[i],... must be connected to each other, and this gives 2^K connections for every i, and (2^K)*N connections in total.
For cases where K is relatively small, like 4 in your example, but N and M are quite big, this algorithm works like a charm. It isn't suitable for situation where K is big though.
I'm not sure if that's clear. Tell me if you need more detailed explanation.
EDIT:
Hope this makes my algorithm more clear.
Black edges have weight 0, and red edges have weight 1.
By using layered graph approach, we translated our special graph into plain weighted graph, so we can just run Dijkstra's algorithm on it.
Sorry for ugly image.
EDIT:
Since max K = 10, we would like to remove 2^K from our time complexity. I believe this can be done by making edges that represent possible hops virtual, instead of physically storing them on adjacency list.

Related

Give minimum permutation weight for edges such that a given set of edge is the Minimum Spanning Tree

Question:
Given a graph of N nodes and M edges, the edges are indexed from 1 -> M. It is guaranteed that there's a path between any 2 nodes.
You need to assign weights for M edges. The weights are in the range of [1...M], and each number can only occur once.
To be shorted, the answer should be a permutation array of [1...M], in which arr[i] = x means edge[i] has the weight of x.
You are given a set R of n-1 edges. R is guaranteed to be a Spanning Tree of the graph.
Find a way to assign weights so that R is the Minimum Spanning Tree of the graph, if there are multiple answers, print the one with minimum lexicographical order.
Contraints:
N, M <= 10^6
Example:
Edges:
3 4
1 2
2 3
1 3
1 4
R = [2, 4, 5]
Answer: 3 4 5 1 2
Explaination:
If you assign weights for the graph like the above image, the MST would be the set R, and it has the smallest lexicographical order.
My take with O(N^2):
Since it asks for the minimum lexicographical order, I traverse through the list of edges, assigning the weights in an increasing order. Intially, w = 1. There can be 3 situations:
If edge[i] is in R, assign weight[i] = w, increase w by 1
If edge[i] is not in R: say edge[i] connect nodes u and v. assign weight and increase w for each edge in the path from u to v in R (if that edge is not assigned yet). Then assign weight and increase w for edge[i]
If edge[i] is assigned, skip it
Is there any way to improve my solution so that it can work in O(N.logN) or less?
Yes, there's an O(m log m)-time algorithm.
The fundamental cycle of a non-tree edge e is comprised of e and the path in the tree between the endpoints of e. Given weights, the spanning tree is minimum if and only if, for every non-tree edge e, the heaviest edge in the fundamental cycle of e is e itself.
The lexicographic objective lends itself to a greedy algorithm, where we find the least valid assignment for edge 1, then edge 2 given edge 1, then edge 3 given the previous edges, etc. Here's the core idea: if the next unassigned edge is a non-tree edge, assign the next numbers to the unassigned tree edges in its fundamental cycle; then assign the next number.
In the example, edge 3-4 is first, and edges 1-3 and 1-4 complete its fundamental cycle. Therefore we assign 1-3 → 1 and 1-4 → 2 and then 3-4 → 3. Next is 1-2, a tree edge, so 1-2 → 4. Finally, 2-3 → 5 (1-2 and 1-3 are already assigned).
To implement this efficiently, we need two ingredients: a way to enumerate the unassigned edges in a fundamental cycle, and a way to assign numbers. My proposal for the former would be to store the spanning tree with the assigned edges contracted. We don't need anything fancy; start by rooting the spanning tree somewhere and running depth-first search to record parent pointers and depths. The fundamental cycle of e will be given by the paths to the least common ancestor of the endpoints of e. To do the contraction, we add a Boolean field indicating whether the parent edge is contracted, then use the path compression trick from disjoint-set forests. The work will be O(m log m) worst case, but O(m) average case. I think there's a strong possibility that the offline least common ancestor algorithms can be plugged in here to get the worst case down to O(m).
As for number assignment, we can handle this in linear time. For each edge, record the index of the edge that caused it to be assigned. At the end, stably bucket sort by this index, breaking ties by putting tree edges before non-tree. This can be done in O(m) time.

Impossible DFS of Directed graph question

Consider the following directed graph. For a given n, the vertices of the graph correspond to the
integers 1 through n. There is a directed edge from vertex i to vertex j if i divides j.
Draw the graph for n = 12. Perform a DFS of the above graph with n = 12. Record the discovery
and finish times of each vertex according to your DFS and classify all the edges of the graph into tree, back, forward, and cross edges. You can pick any start vertex (vertices) and any order of visiting the vertices.
I do not see how it is possible to traverse this graph because of the included stipulations. It is not possible to get a back edge because a dividing a smaller number by a larger number does not produce an integer and will never be valid.
Say we go by this logic and create a directed graph with the given instructions. Vertex 1 is able to travel to vertex 2, because 2 / 1 is a whole number. However, it is impossible to get to vertex 3 as vertex 2 can only travel to vertex 4, 6, 8, or 10. Since you cannot divide by a bigger number it will never be possible to visit a lower vertex once taking one of these paths and therefore not possible to reach vertex 3.
Your assumption about the back tracks is correct. You cannot have back tracks because you don't have any circles. Consider the following example:
When we start at 2 we will find the edges 2->4, 4->8, 4->12, 2->6 and 2->10. The edges 2->8 and 2->12 are forward edges, they are like shortcuts to get forward much faster. The edge 6->12 is a cross edge because you are switching from one branch to another branch. And since we have no circles to somehow get back to a previous node, we don't have any backward edges.

Write Algorithm for changing non-directional graph to directional

I need help to solve this question :
you have undirected graph G=(V,E) you want to write an algorithm to adjust all
One of the edges, so that in the directed graph obtained, he number of incoming edges into the node be always greater than zero.
for all edge {u,v} ∈ E you should chose one direction (u,v) or (v,u).
When the answer is positive, the algorithm must return the intention of the edges - which fulfills the requirement
As was pointed out, this problem clearly does not always have a solution. Since every vertex must have at least one incoming edge, if we have E < V, the problem is impossible.
So, let's assume that we have E >= V. Here is one way to approach the algorithm: First, count the number of edges attached to each vertex in O(E) time. Note, my solution assumes appropriate storage like an adjacency list. Can you see why an adjacency matrix would have a worse complexity?
Second, we will make a binary minheap of the vertices, according to their corresponding edge count, in O(V). Some intuition: if we have a vertex with only one edge, we must convert that into an incoming edge! When we assign the direction of that edge, we need to update the edge count of the vertex on the other side. If that other vertex goes from 2 edges to 1, we now are forced to assign the direction of its one edge left. Visually:
1 - 2 - 1
Arbitrarily choose a 1 edge count to make directed
1 - 2 -> 0
2 just lost an edge, so update to 1!
1 - 1 -> 0
Since it only has 1 edge now, convert its edge to be incoming!
0 -> 0 -> 0
Obviously this graph doesn't work since V > E, but you get the idea.
So, V times, we extract the minimum from the heap and fix in O(logV). Each time, decrement the edge count of the neighbor. Assuming the adjacency list, we can find a neighbor (first element) and update the count in O(1), and we can fix the heap again in O(logV). Overall, this step takes O(V logV).
Note, if all of our remaining vertices have more than one possible edge, this approach will arbitrarily select one of the vertices with a smallest edge count and arbitrarily select one of its edges. I will let you think about why this works (or try to provide a counter-example if you think it doesn't!) Finally, if E > V, then when we finish, there may be extra unnecessary edges left over. In O(E) time, we can arbitrarily assign directions to those edges.
Overall, we are looking at V + V*logV + E aka O(E + VlogV). Hope this helps!

Detecting connectedness of nodes over a long time in a graph

I start out with a graph of N nodes with no edges.
Then I procede to take M predetermined steps.
At each step, I must either create an edge between two nodes, or delete an edge.
After each step, I must print out how many connected components there are in my graph.
Is there an algorithm for solving this problem in time linear with respect to M? If not, is there one better than O(min(M,N) * M) in the worst case?
EDIT:
The program does not get to decide what the M steps are.
I have to read from the input, whether I am supposed to create an edge or delete it, and also which edge I am supposed to create/delete.
So example input might be
N = 4
M = 4
JOIN 1 2
JOIN 2 3
DELETE 2 3
DELETE 1 2
Then my output should be
3 # (1 2) 3 4
2 # (1 2 3) 4
3 # (1 2) 3 4
4 # 1 2 3 4
There are ways to solve this problem fully online, but they're more complicated than this answer. The algorithm that I'm proposing is to maintain a spanning forest of the available edges, together with the number of components of the spanning forest (and hence the graph). If we were attacking this problem fully online, then this would be problematic, since a spanning forest edge might get deleted, leaving us to paw through the unused edges for a replacement. We know, however, how soon each edge currently in the graph will be deleted.
The particular spanning forest that we maintain is a maximum-weight spanning forest, where the weight of each edge is its deletion time. If an edge belonging to this spanning forest is deleted, then there is no replacement, since every other edge connecting the components represented by its endpoints either hasn't been inserted yet or, having lesser weight, has already been deleted.
There's a dynamic tree data structure, also referred to as a link/cut tree, due to Sleator and Tarjan, that can be made to provide the following operations in logarithmic time.
Link(u, v, w) - inserts an edge between u and v with weight w;
u and v must not be connected already
Cut(u, v) - cuts the edge between u and v, if it exists;
returns a boolean indicating whether an edge was removed
FindMin(u, v) - finds the minimum-weight edge on the path from u to v
and returns its endpoints and weight;
returns null if either u = v or u and v are not connected
To maintain the forest, when an edge from u to v is inserted, compare its removal time to the minimum on the path from u to v. If the minimum does not exist, then insert the edge. If the minimum is less than the new edge, delete the minimum and replace it with the new edge. Otherwise, do nothing. When an edge from u to v is deleted, attempt to delete it from the forest.
The running time of this approach is O(m log n). If you don't have a dynamic tree handy, then it admittedly will take quite a while to implement. Instead of using a proper dynamic tree, I've had success with a much simpler data structure that just stores the forest as a bunch of nodes with weights and parent pointers. The running time then is O(m d) where d is the maximum diameter of the graph, and if you're lucky, d is quite a lot less than n.

Total cycles in a Undirected graph

Given an undirected graph with N vertices and M edges I need to find the number of cycles in the graph. But there is a constraint.
Here is an example of it:
Consider this graph with 6 vertices and 7 edge pairs :- A-B , B-C , C-F , A-D , D-E , E-F , B-E.
Here is the image for better understanding :
Then here 2 cycles should be counted that are A-B-E-D-A and B-C-F-E-B but not A-B-C-F-E-D-A
So I need to find the count of the total cycles in the graph.
I think you are looking for a cycle basis of your graph. You do that by finding any spanning tree of the graph (for example a DFS or BFS tree). The non-tree edges of the graph represent a cycle basis: If you connect the endpoints by the unique path through the tree, you get an element of the basis.
So if the graph is connected, the number of basis elements is m - n + 1 (m = number of edges, n = number of nodes). If it's not connected, just decompose it into connected components and sum up the number of basis elements of the components. You get something like m - n + c where c is the number of connected components. Thus, if you're not interested in the actual cycles and only in their count, you just need to find the number of connected components. You can use DFS or BFS for that as well.

Resources