Ecco una soluzione basata sulle idee nella risposta di Realz Slaw. Fondamentalmente è una riesposizione delle sue idee che potrebbe essere più chiara o più facile da seguire. Il piano è che procederemo in due fasi:
In primo luogo, si costruirà un grafico con la seguente struttura: qualsiasi percorso da s a t in S è un cammino minimo da s a t in G , ed ogni cammino minimo da s a t in G è presente anche in S . Pertanto, S contiene esattamente i percorsi più brevi in G : tutti i percorsi più brevi e niente di più. Come succede, S sarà un DAG.SstSstGstGSSGS
Successivamente, si campionare uniformemente a caso da tutti i percorsi da a t in S .stS
Questo approccio si generalizza a un grafico diretto arbitrario , purché tutti i bordi abbiano un peso positivo, quindi spiegherò il mio algoritmo in questi termini. Lascia che w ( u , v ) indichi il peso sul bordo u → v . (Questo generalizza l'affermazione del problema che hai dato. Se hai un grafico non ponderato, supponi solo che ogni bordo abbia peso 1. Se hai un grafico non orientato, tratta ogni bordo non orientato ( u , v ) come i due bordi diretti u → v e v → u .)Gw(u,v)u→v(u,v)u→vv→u
Fase 1: estratto di . S Esegui un algoritmo di percorsi più brevi a sorgente singola (ad esempio, l'algoritmo di Dijkstra) su , a partire dalla sorgente s . Per ogni vertice v in G , d ( s , v ) denota la distanza da s a v .GsvGd(s,v)sv
Ora definisci il grafico come segue. È costituito da ogni bordo u → v tale che (1) u → v sia un bordo in G e (2) d ( s , v ) = d ( s , u ) + w ( u , v ) .Su→vu→vGd(s,v)=d(s,u)+w(u,v)
Il grafico ha alcune proprietà convenienti:S
Ogni percorso più breve da a t in G esiste come percorso in S : un percorso più breve s = v 0 , v 1 , v 2 , … , v k = t in G ha la proprietà che d ( s , v i + 1 ) = d ( s , v i ) + w ( v i , v istGSs=v0,v1,v2,…,vk=tGd(s,vi+1)=d(s,vi)+w(vi,vi+1), so the edge vi→vi+1 is present in S.
Every path in S from s to t is a shortest path in G. In particular, consider any path in S from s to t, say s=v0,v1,v2,…,vk=t. Its length is given by the sum of the weights of its edges, namely ∑ki=1w(vi−1,vi)S∑ki=1(d(s,vi)−d(s,vi−1)d(s,t)−d(s,s)=d(s,t). Therefore, this path is a shortest path from s to t in G.
Finally, the absence of zero-weight edges in G implies that S is a dag.
Step 2: sample a random path. Now we can throw away the weights on the edges in S, and sample a random path from s to t in S.
To help with this, we will do a precomputation to compute n(v) for each vertex v in S, where n(v) counts the number of distinct paths from v to t. This precomputation can be done in linear time by scanning the vertices of S in topologically sorted order, using the following recurrence relation:
n(v)=∑w∈succ(v)n(w)
where succ(v) denotes the successors of v, i.e., succ(v)={w:v→w is an edge in S}, and where we have the base case n(t)=1.
Next, we use the n(⋅) annotation to sample a random path. We first visit node s. Then, we randomly choose one of the successors of s, with successor w weighted by n(w). In other words:
choosesuccessor(v):
n = 0
for each w in succ(w):
n = n + n(w)
r = a random integer between 0 and n-1
n = 0
for each w in succ(w):
n = n + n(w)
if r < n:
return w
To choose a random path, we repeatedly iterate this process: i.e., v0=s, and vi+1= choosesuccessor
(vi). The resulting path is the desired path, and it will be sampled uniformly at random from all shortest paths from s to t.
Hopefully this helps you understand Realz Slaw's solution more easily. All credit to Realz Slaw for the beautiful and clean solution to this problem!
The one case this doesn't handle is the case where some edges have weight 0 or negative weight. However, the problem is potentially not well-defined in that case, as you can have infinitely many shortest paths.