Reputation: 25812
Here is the exercise:
Let v and w be two vertices in a directed graph G = (V, E). Design a linear-time algorithm to find the number of different shortest paths (not necessarily vertex disjoint) between v and w. Note: the edges in G are unweighted
For this excise, I summarise as follows:
From the points above, I have the following thoughts:
count
for the number of shortest pathsglobal level
informationglobal level
by one each time then BFS reaches a new levelshortest level
info for shortest path to wglobal level
to the shortest level
and count++
; global level
equals to the shortest level
, I increase count
each time I met w again.global level
becomes bigger than the shortest level
, I terminate the travelling, because I am looking for shortest path not path.Is my algorithm correct? If I do v to w and then w to v, is that still considered as linear-time?
Upvotes: 28
Views: 51171
Reputation: 2847
Just check the good explanation given here:
https://www.geeksforgeeks.org/number-shortest-paths-unweighted-directed-graph/
Briefly, we can modify any shortest path algorithm, and when the update step comes increases a counter for the number of shortest path previous discovered when the current path proposal has the same length of the shortest path found until that moment.
In the particular case, when it's a graph unweighted or with constant weight for all edges, the easiest way is to modify a BFS.
Upvotes: 0
Reputation: 1632
Simplest solution by changing BFS:
count(v) = 0, count(s) = 1. for every neighbour u of v, if(d(v) + 1 == d(u)), then count(u) += count(v). now reset everything and do the same from the end vertex.
Upvotes: 2
Reputation: 10658
Here are some ideas on this.
Proof: If there are multiple paths entering x
through the same vertex there are obviously multiple ways through x
. This is simple. Now let us assume there is only one way into x
through each vertex going into x
(at maximum).
If x has been encountered before, none of the current paths can contribute to another shortest path. Since x has been encountered before, all paths that can follow will be at least one longer than the previous shortest path. Hence none of these paths can contribute to the sum.
This means however we encounter each node at most once and are done. So a normal BFS is just fine.
This can be compiled into a very simple algorithm, which is mainly just BFS.
- Mark nodes as visited as usual with BFS.
- Instead of adding just nodes to the queue in the DFS add nodes plus number of incoming paths.
- If a node that has been visited should be added ignore it.
- If you find a node again, which is currently in the queue, do not add it again, instead add the counts together.
- Propagate the counts on the queue when adding new nodes.
- when you encounter the final, the number that is stored with it, is the number of possible paths.
Upvotes: 24
Reputation: 39
int edgeCb( graphPT g, int x, int y )
{
if ( dist[ y ] > dist[ x ] + 1 ) {
dist[ y ] = dist[ x ] + 1; // New way
ways[ y ] = ways[ x ]; // As many ways as it's parent can be reached
} else if ( dist[ y ] == dist[ x ] + 1 ) {
ways[ y ] += ways[ x ]; // Another way
} else {
// We already found a way and that is the best
assert( dist[ y ] < g->nv );
}
return 1;
}
Above code is giving me proper results for all kind of graphs mentioned in this post. Basically it is a edge callback for the BFS traversal.
dist[ start ] = 0; ways[ start ] = 1;
for rest all vertices dist[ x ] = numberOfVertices; // This is beyond the max possible disatance
BFS( g, start );
If ways[ end ] is not zero then that represents the number of ways and dist[ end ] represents the shortest distance.
Incase ways[ end ] == 0 means end can't be reached from start.
Please let me know if there are any loop holes in this.
Upvotes: 2
Reputation: 339
Can i do it this way
From the level table, i start traversing back counting the number of parents to the vertex in our path(first time it would be the destination vertex).
At every step, I multiply the number of distinct parents found at that particular level to the the shortest paths I can have to the destination vertex.
I move up the levels, only considering the nodes that fall into my path and multiply the number of distinct parents found at each level till I reach the level 0.
Does this work?
Upvotes: 0
Reputation: 1627
As qrqrq shows, your algorithm fails on some graphs, but the idea of BFS is good. Instead, maintain an array z
of size |V|
which you initialize to zero; keep the number of shortest paths to a discovered vertex i
at distance less than level
in z[i]
. Also maintain an array d
of size |V|
such that d[i]
is the distance from v
to vertex i
if that distance is less than level
. Initialize level
to 0, d[v]
to 0, and z[v]
to 1 (there is a single path of length 0 from v
to v
), and set all other entries of d
to -1
and of z
to 0
.
Now whenever you encounter an edge from i
to j
in your BFS, then:
d[j] = -1
, then set d[j] := level
and z[j] := z[i]
.d[j] = level
, then set z[j] := z[j] + z[i]
.The reason is that for every shortest path from v
to i
, there is one shortest path from v
to j
. This will give the number of shortest paths from v
to each vertex in linear time. Now do the same again but starting from w
.
Upvotes: 4
Reputation: 134
Your algorithm breaks on a graph like
* * * 1
/ \ / \ / \ / \
v * * * w
\ / \ / \ / \ /
* * * 2
with all edges directed left to right. It counts two paths, one through 1
and the other through 2
, but both 1
and 2
can be reached from v
by eight different shortest paths, for a total of sixteen.
Upvotes: 10
Reputation: 13908
This algorithm looks correct to me.
BFS, as you know, is a linear time (O(N)
) search because the time T
required to complete it is, at worst, T = C + a * N
, where N
is the number of nodes and C
, a
are any fixed constants.
In your case, performing the search twice - first from v
to w
, and then from w
to v
- is (at worst) 2T
, or 2C + 2a * N
, which also satisfies the linear time requirement O(N)
if you define a new C' = 2C
, and a new a' = 2a
, because both C'
and a'
are also fixed constants.
Upvotes: 2