Detecting connectedness of nodes over a long time in a graph - algorithm

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.

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.

Minimum Hop Count in Directed Graph based on Conditional Statement

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.

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!

Is this a proper algorithm that would accept graph G if it's connected?

I wanted to ask and see if this suffices in creating a polynomial time algorithm given a Graph P? Just want to double check.
On input (P,u,v) where P is an undirected graph with nodes u and v:
Create a list D of every edge in graph P with numbers from x_0 to x_k.
Select node u as the starting node. Utilizing BFS, traverse through the graph until the current node is the initial u value.
Repeat with using x_0 onwards through the list until x_k is used.
If BFS completes, accept. Otherwise, reject.
I believe my problem lets with the accept/rejection condition but what would it be in this case?
Your question doesn't make sense in a lot of ways, but from what I can tell, no.
Your step 2 will (slowly) find a cycle, which is not useful.
I have no clue what step 3 is supposed to be and your variable v is unused (and having u as as parameter doesn't make sense).
For an directed graph, you need to specify whether you want to check for weak connectivity (like a undirected graph) or strong connectivity.
For weak connectivity, you need to:
Take as input a graph G
Create a local, empty, set S for seen nodes.
Do a depth first search (including backwards links - watch your algorithmic complexity with how you look them up!) from some node, adding each node to S as you visit it, and skipping edges that lead from the current node to a node in S during iteration. (You can use a breadth-first search if you allocate an additional data set for the frontier)
Check whether S has the same number of nodes as G.
For strong connectivity, you need to check that the graph is connected regardless of which node you set at. There's probably a way to do this more efficiently than repeating the above for every node.
An example graph (consider this from any starting node):
1 -> 2
2 -> 3
3 -> 1
3 -> 4
4 -> 5
5 -> 6
6 -> 4

Shortest path in absence of the given edge

Suppose we are given a weighted graph G(V,E).
The graph contains N vertices (Numbered from 0 to N-1) and M Bidirectional edges .
Each edge(vi,vj) has postive distance d (ie the distance between the two vertex vivj is d)
There is atmost one edge between any two vertex and also there is no self loop (ie.no edge connect a vertex to
itself.)
Also we are given S the source vertex and D the destination vertex.
let Q be the number of queries,each queries contains one edge e(x,y).
For each query,We have to find the shortest path from the source S to Destination D, assuming that edge (x,y) is absent in original graph.
If no any path exists from S to D ,then we have to print No.
Constraints are high 0<=(N,Q,M)<=25000
How to solve this problem efficiently?
Till now what i did is implemented the simple Dijakstra algorithm.
For each Query Q ,everytime i am assigning (x,y) to Infinity
and finding Dijakstra shortest path.
But this approach will be very slow as overall complexity will be Q(time complexity of Dijastra Shortes path)*
Example::
N=6,M=9
S=0 ,D=5
(u,v,cost(u,v))
0 2 4
3 5 8
3 4 1
2 3 1
0 1 1
4 5 1
2 4 5
1 2 1
1 3 3
Total Queries =6
Query edge=(0,1) Answer=7
Query edge=(0,2) Answer=5
Query edge=(1,3) Answer=5
Query edge=(2,3) Answer=6
Query edge=(4,5) Answer=11
Query edge=(3,4) Answer=8
First, compute the shortest path tree from source node to destination.
Second, loop over all the queries and cut the shortest path at the edge specified by the query; this defines a min-cut problem, where you have the distance between the source node and the frontier of one partition and the frontier of the another and the destination; you can compute this problem very easily, at most O(|E|).
Thus, this algorithm requires O(Q|E| + |V|log|V|), asymptotically faster than the naïve solution when |V|log|V| > |E|.
This solution reuses Dijkstra's computation, but still processes each query individually, so perhaps there are room to improvements by exploiting the work did in a previous query in successive queries by observing the shape of the cut induced by the edge.
For each query the graph changes only very slightly, so you can reuse a lot of your computation.
I suggest the following approach:
Compute the shortest path from S to all other nodes (Dijkstras Algorithm does that for you already). This will give you a shortest path tree T.
For each query, take this tree, pruned by the edge (x,y) from the query. This might be the original tree (if (x,y) was no where on the tree) or a smaller tree T'.
If D is in the T', you can take the original shortest path
Otherwise start Dijkstra, but use the labels you already have from the T' (these paths are already smallest) as permanent labels.
If you run the Dijkstra in step 2 you can reuse the pruned of part of tree T in the following way: Every time you want to mark a node permanent (which is one of the nodes not in T') you may attach the entire subtree of this node (from the original tree T) to your new shortest path tree and label all its nodes permanent.
This way you reuse as much information as possible from the first shortest path run.
In your example this would mean:
Compute shortest path tree:
0->1->2->3->4->5
(in this case a very simple)
Now assume we get query (1,2).
We prune edge (1,2) leaving us with
0->1
From there we start Dijkstra getting 2 and 3 as next permanent marked nodes.
We connect 1 to 2 and 1 to 3 in the new shortest path tree and attach the old subtree from 3:
2<-0->1->3->4->5
So we got the shortest path with just running one additional step of Dijkstras Algorithm.
The correctness of the algorithm follows from all paths in tree T being at most as long as in the new Graph from the Query (where every shortest path can only be longer). Therefore we can reuse every path from the tree that is still feasible (i.e. where no edge was removed).
If performance matters a lot, you can improve on the Dijkstra performance through a lot of implementation tricks. A good entry point for this might be the DIMACS Shortest Path Implementation Challenge.
One simple optimization: first run Dijkstra on complete graph (with no edges removed).
Then, for each query - check if the requested edge belongs to that shortest path. If not - removing this edge won't make any difference.

Resources