Hier ist eine Lösung, die auf den Ideen in der Antwort von Realz Slaw basiert. Es ist im Grunde eine Neuausstellung seiner Ideen, die klarer oder leichter zu befolgen sein könnte. Der Plan ist, dass wir in zwei Schritten vorgehen:
Zunächst erstellen wir einen Graphen mit der folgenden Eigenschaft: Jeder Weg von s nach t in S ist ein kürzester Weg von s nach t in G , und jeder kürzeste Weg von s nach t in G ist auch in S vorhanden . Somit enthält S genau die kürzesten Wege in G : alle kürzesten Wege und nichts weiter. Wie es passiert, wird S eine DAG sein.SstSstGstGSSGS
Als nächstes werden wir alle Pfade von bis t in S gleichmäßig zufällig abtasten .stS
Dieser Ansatz verallgemeinert sich auf einen willkürlich gerichteten Graphen , solange alle Kanten ein positives Gewicht haben. Deshalb erkläre ich meinen Algorithmus in diesen Begriffen. Sei w ( u , v ) das Gewicht an der Kante u → v . (Dies verallgemeinert die Problemaussage, die Sie gegeben haben. Wenn Sie ein ungewichtetes Diagramm haben, nehmen Sie einfach an, dass jede Kante das Gewicht 1 hat. Wenn Sie ein ungerichtetes Diagramm haben, behandeln Sie jede ungerichtete Kante ( u , v ) als die zwei gerichteten Kanten u → v und v → uGw(u,v)u→v(u,v)u→vv→u .)
Schritt 1: Extrakt . S Führen Sie einen Single-Source-Shortest-Path-Algorithmus (z. B. Dijkstra-Algorithmus) auf , beginnend mit Quelle s . Für jeden Eckpunkt v in G bezeichne d ( s , v ) den Abstand von s zu v .GsvGd(s,v)sv
Now define the graph S as follows. It consists of every edge u→v such that (1) u→v is an edge in G, and (2) d(s,v)=d(s,u)+w(u,v).
The graph S has some convenient properties:
Every shortest path from s to t in G exists as a path in S: a shortest path s=v0,v1,v2,…,vk=t in G has the property that d(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), but by the definition of S, this sum is ∑ki=1(d(s,vi)−d(s,vi−1), which telescopes to 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.