Suppose there are 3 target nodes in a graph.
A vertex-disjoint path means there is not any same node except the end nodes during the path.
For any one single node, say node i, how to find all vertex-disjoint paths from node i to the three target nodes?
You can solve this problem by reducing it to a max-flow problem in an appropriately-constructed graph. The idea is as follows:
Split each node v in the graph into to nodes: vin and vout.
For each node v, add an edge of capacity one from vin to vout.
Replace each other edge (u, v) in the graph with an edge from uout to vin of capacity 1.
Add in a new dedicated destination node t.
For each of the target nodes v, add an edge from vin to t with capacity 1.
Find a max-flow from sout to t. The value of the flow is the number of node-disjoint paths.
The idea behind this construction is as follows. Any flow path from the start node s to the destination node t must have capacity one, since all edges have capacity one. Since all capacities are integral, there exists an integral max-flow. No two flow paths can pass through the same intermediary node, because in passing through a node in the graph the flow path must cross the edge from vin to vout, and the capacity here has been restricted to one. Additionally, this flow path must arrive at t by ending at one of the three special nodes you've identified, then following the edge from that node to t. Thus each flow path represents a node-disjoint path from the source node s to one of the three destination nodes. Accordingly, computing a max-flow here corresponds to finding the maximum number of node-disjoint paths you can take from s to any of the three destinations.
Hope this helps!
Related
Given an undirected weighted graph, a start, and an end point. You need to find the shortest path to that end point, but throw an error if multiple shortest paths are found. How would we do the error part? Is there a way to check if multiple shortest paths to a destination node exist?
My idea is that when we pop out of the priority queue in dijkstra's algorithm, at that time if the node is the destination node, then we check if in this priority queue, another element exists for the same destination node.
During the relaxation, instead of only pushing to the queue if the distance is less than, we can push if the distance is less than or equal to. But I am not sure about it.
EDIT - Its a weighted undirected graph
One way to do this is by creating a shortest path DAG. Whenever you relax some edge from node A to node B with cost C (assuming the current shortest distance from source to each node is stored in array dist), if dist[A] + C is greater than dist[B] then do nothing, if dist[A] + C is equal to dist[B], then we can reach B in a shortest path using a different route than before, so we add A to the list of nodes that can reach B in its shortest path (let's call this array pars), so we add A to pars of B, and finally if dist[A] + C is less than dist[B], then we update dist[B] and clear the previous values from pars[B], and add A to pars[B].
The resulting graph is guaranteed to be a DAG if all edge weights are strictly greater than 0. Then you can count the number of paths to the destination node using some easy dynamic programming methods, process node in a topological order, then the number of paths of each node is the sum of number of paths of nodes that reach it (nodes in pars[node]).
Hopefully this was useful and clear.
My idea of solving this problem is to adjust DFS so that it stops when we hit the destination node, then set up a counter that adds up all of the neighbors of the starting node, then the neighbors of the starting node and its neighrbours recursively.
I'm just wondering if this will only count the paths from the source to the destination, and not any stray paths that don't lead to the destination node.
Thank you for the help.
You can use dynamic programming. You have a directed acyclic graph so you have a node (say s) with no arcs pointing into s. You also have a node (say t) that has no arcs pointing out of t. Because it is acyclic, you can use a topological sorting algorithm to find an ordering of the nodes such that every arc points away from s and towards t.
So start at s. The number of paths from s to s is 1, the empty path. Because the graph is acyclic, s must have a neighbour u such that the only arc pointing into u is su. Now you just repeat. In general, for a node w that has arcs from v1,...vk pointing into it. Then the number of paths from s to w is just the sum of the number of sv1 paths, ..., svk paths.
This is in the case of a single arc between each node. If there are multiple arcs you multiply so it would be (number of v1w arcs)(number of sv1paths) + ... + (number of vkw arcs)(number of svk paths)
And at each step you can use the fact that it is acyclic to find the node w such that you have already calculated all the sv1 to svk paths.
I would use BFS.
Let's call the source node s and the target node t.
When you BFS starting from s, all the paths with length 1 will be found and put into a queue. You can, then, take the first element of the queue (call it u) and find all the paths of size 2 (s -> u -> ...). Repeat the same thing for each distance, until you find all paths of all lengths from s to t.
A trick to speed it up would be: after you exhausted all the paths of a node w, store how many paths from w to t there are, and when another node (above w) reach w, you won't need to recompute all the paths.
Given a network flow G(V,E). After we run FF algorithm and get a residual grpah Gf and a min-cut (S,T)
I want to know a minimum number of edges Eā²ā E such that increasing capacity of each e ā E by one unit will increase the max flow to val(f)+1. The algorithm should run in O(E*log(V)).
Here is my approach.
For each cross edge (u,v)
(1) Use BFS to find partial augmenting path s to u; and all partial augmenting path from v to t. If both such partial augmenting path exists. Then increase the (u,v) can make max flow increase by one.
If (1) is false,
There are few possibility
(a) In residual, source s has no outgoing edge
(b) In residual, sink t has no incoming edge.
(c) both of above happens
In case of (a), the min-cut has one set contains only source s. Find the shortest path from cross edge to t, this distance + 1 (the cross edge) will be our minimal. By using Dijlstra algorithm in O(E*log(V)) time
In case of (b), similarly, find the shortest path from a cross edge to t (let's say this cross edge is (u,v) and v in T, v to t is the shortest path for all cross edge), this distance + 1 + the distance of shortest path from s to u = minimal number of edges that increase all its capacity by one, leads to max flow increase by one
In case of (c), we need to look for a shortest path from s to t; we can apply Dijlstra algorithm in O(E*log(V)) time.
However, I think the above approach can achieve the goal but not very efficient (especially in dealing with case (2), it might not run in E*log(V) time).
Is there easier way of approaching?
If capacities are integers then this seems reasonably straightforward.
From S use depth first search to find all of the nodes reachable from there using links with spare capacity. Put these nodes in a set and mark them.
From T use depth first search to find all of the nodes that can reach T using links with spare capacity. Mark these nodes differently.
Use breadth first search to find the shortest path from any node reachable from S to any node that can reach T. Start with the set of nodes reachable from S. At each stage look it see if any node that can reach T is a neighbour of a node in the current set. If so then you are finished. If not, then the set for the next stage is the set of neighbours of nodes in the current set that are not marked. Mark all of the nodes in the new set.
If the capacities are not integers, so that creating any flow does not give you a flow of capacity at least one, then I think you are in the land of https://en.wikipedia.org/wiki/Minimum-cost_flow_problem.
I have to ensure that a graph in our application is a DAG with a unique source and a unique sink.
Specifically I have to ensure that for a given start node and end node (both of which are known at the outset) that every node in the graph lies on a path from the start node to the end node.
I already have an implementation of Tarjan's algorithm which I use to identify cycles, and a a topological sorting algorithm that I can run once Tarjan's algorithm reports the graph is a DAG.
What is the most efficient way to make sure the graph meets this criterion?
If your graph is represented by an adjacency matrix, then node x is a source node if the xth column of the matrix is 0 and is a sink node if row x of the matrix is 0. You could run two quick passes over the matrix to count the number of rows and columns that are 0s to determine how many sources and sinks exist and what they are. This takes time O(n2) and is probably the fastest way to check this.
If your graph is represented by an adjacency list, you can find all sink nodes in time O(n) by checking whether any node has no outgoing edges. You can find all sinks by maintaining for each node a boolean value indicating whether it has any incoming edges, which is initially false. You can then iterate across all the edges in the list in time O(n + m) marking all nodes with incoming edges. The nodes that weren't marked as having incoming edges are then sources. This process takes time O(m + n) and has such little overhead that it's probably one of the fastest approaches.
Hope this helps!
A simple breadth or depth-first search should satisfy this. Firstly you can keep a set of nodes that comprise sink nodes that you've seen. Secondly, you can keep a set of nodes that you've discovered using BFS/DFS. Then the graph will then be connected iff there is a single connected component. Assuming you're using some kind of adjacency list style representation for your graph, the algorithm would look something like this:
create an empty queue
create an empty set to store seen vertices
create an empty set for sink nodes
add source node to queue
while queue is not empty
get next vertex from queue, add vertex to seen vertices
if num of adjacent nodes == 0
add sink nodes to sink node set
else
for each node in adjacent nodes
if node is not in seen vertices
add node to queue
return size of sink nodes == 1 && size of seen vertices == total number in graph
This will be linear in the number of vertices and edges in the graph.
Note that as long as you know a source vertex to start from, this will also ensure the property of a single source: any other vertex that is a source won't be discovered by the BFS/DFS, and thus the size of the seen vertices won't be the total number in the graph.
If your algorithm takes as input a DAG, which is weakly connected, assume that there are only one node s whose in-degree is zero and only one node t whose out-degree is zero, while all other nodes have positive in-degree and out-degree, then s can reach all other nodes, and all other nodes can reach t. By contradiction, assume that there is a node v that s cannot reach. Since no nodes can reach s, that is, v cannot reach s too. As such, v and s are disconnected, which contradicts the assumption. On the other hand, if the DAG is not weakly connected, it definitely does not satisfy the requirements that you want. In sum, you can first compute the weakly connected component of the DAG simply using BFS/DFS, meanwhile remembering the number of nodes whose in-degree or out-degree is zero. The complexity of this algorithm is O(|E|).
First, do a DFS on the graph, starting from the source node, which, as you say, is known in advance. If you encounter a back edge[1], then you have a cycle and you can exit with an error. During this traversal you can identify if there are nodes, not reachable from the source[2] and take the appropriate action.
Once you have determined the graph is a DAG, you can ensure that every node lies on a path from the source to the sink by another DFS, starting from the source, as follows:
bool have_path(source, sink) {
if source == sink {
source.flag = true
return true
}
// traverse all successor nodes of `source`
for dst in succ(source) {
if not dst.flag and not have_path(dst, sink)
return false // exit as soon as we find a node with no path to `sink`
}
source.flag = true;
return true
}
The procedure have_path sets a boolean flag in each node, for which there exists some path from that node to the sink. In the same time the procedure traverses only nodes reachable from the source and it traverses all nodes reachable from the source. If the procedure returns true, then all the nodes, reachable from the source lie on a path to the sink. Unreachable nodes were already handled in the first phase.
[1] an edge, linking a node with a greater DFS number to an node with a lesser DFS number, that is not already completely processed, i.e. is still on the DFS stack
[2] e.g. they would not have an assigned DFS number
Given an undirected graph G = (V, E), the edges in G have non-negative weights.
[1] how to find all the edge-disjoint and equal-cost paths between two nodes s and t ?
[2] how to find all the edge-disjoint paths between two nodes s and t ?
[3] how to find all the vertex-disjoint and equal-cost paths between two nodes s and t ?
[4] how to find all the vertex-disjoint paths between two nodes s and t ?
Any approximation algorithms instead ?
Build a tree where each node is a representation of a path through your unidirectional graph.
I know, a tree is a graph too, but in this answer I will use the following terms with this meanings:
vertex: is a vertex in your unidirectional graph. It is NOT a node in my tree.
edge: is an edge in your unidirectional graph. It is NOT part of my tree.
node: a vertex in my tree, not in your graph.
root: the sole node on top of my tree that has no parent.
leaf: any node in my tree that has no children.
I will not talk about edges in my tree, so there is no word for tree-edges. Every edge in this answer is part of your graph.
Algorithm to build the tree
The root of the tree is the representation of a path that contains only of the vertex s and contains no edge. Let its weight be 0.
Do for every node in that tree:
Take the end-vertex of the path represented by that node (I call it the actual node) and find all edges that lead away from that end-vertex.
If: there are no edges that lead away from this vertex, you reached a dead end. This path never will lead to vertex t. So mark this node as a leaf and give it an infinite weight.
Else:
For each of those edges:
add a child-node to the actual node. Let it be a copy of the actual node. Attach the edge to the end of path and then attach the edges end-vertex to the path too. (so each path follows the pattern vertex-edge-vertex-edge-vertex-...)
Now traverse up in the tree, back to the root and check if any of the predecessors has an end-vertex that is identic with the just added end-vertex.
If you have a match, the newly generated node is the representation of a path that contains a loop. Mark this node as a leaf and give it an infinite weight.
Else If there is no loop, just add the newly added edges weight to the nodes weight.
Now test, if the end-vertex of the newly generated node is the vertex t.
If it really is, mark this node as a leaf, since the path represented by this node is a valid path from s to t.
This algorithm always comes to an end in finite time. At the end you have 3 types of leafs in your tree:
nodes that represent dead ends with an infinite weight
nodes that represent loops, also with an infinite weight
nodes that represent a valid path from s to t, with its weight beeing the sum of all edges weights that are part of this path.
Each path represented by a leaf has its individual sequence of edges (but might contain the same sequence of vertexes), so the leafs with finite weights represent the complete set of edge-disjoint pathes from s to t. This is the solution of exercise [2].
Now do for all leafs with finite weight:
Write its weight and its path into a list. Sort the list by the weights. Now paths with identic weight are neighbours in the list, and you can find and extract all groups of equal-cost paths in this sorted list. This is the solution of exercise [1].
Now, do for each entry in this list:
add to each path in this list the list of its vertexes. After you have done this, you have a table with this columns:
weight
path
1st vertex (is always s)
2nd vertex
3rd vertex
...
Sort this table lexigraphic by the vertexes and after all vertexes by the weight (sort by 1st vertex, 2nd vertex, 3rd vertex ,... ,weight)
If one row in this sorted table has the same sequence of vertexes as the row before, then delete this row.
This is the list of all vertex-disjoint paths between two nodes s and t, and so it is the solution of exercise [4].
And in this list you find all equal-cost paths as neighbours, so you can easily extract all groups of vertex-disjoint and equal-cost paths between two nodes s and t from that list, so here you have the solution of exercise [3].