Ось рішення, що базується на ідеях у відповіді Реалза Слау. В основному це повторне викладення його ідей, які можуть бути зрозумілішими або легшими слідувати. План полягає в тому, що ми будемо діяти у два етапи:
По- перше, ми будемо будувати граф S з наступним властивістю: будь-який шлях від S до т в S являє собою найкоротший шлях від S до т в G , і кожен найкоротший шлях від S до т в G також присутній в S . Таким чином, S містить саме найкоротші шляхи в G : всі найкоротші шляхи, і більше нічого. Як це відбувається, S буде DAG.SstSstGstGSSGS
Далі, ми будемо пробувати рівномірно випадковим чином з усіх шляхів від х до т в S .stS
Цей підхід узагальнює довільно спрямований графік G до тих пір, поки всі ребра мають позитивну вагу, тому я поясню свій алгоритм у цих термінах. Нехай w ( u , v ) позначає вагу на межі u → v . (Це узагальнює задане, яке ви подали. Якщо у вас незважений графік, просто припустіть, що кожен край має вагу 1. Якщо у вас є ненаправлений графік, розглядайте кожен непрямий край ( u , v ) як два спрямовані ребра u → v і v → у .)Gw(u,v)u→v(u,v)u→vv→u
Крок 1: екстракт S . S Запустіть алгоритм найкоротших шляхів з одним джерелом (наприклад, алгоритм Дейкстри) на G , починаючи з джерела s . Для кожної вершини v в G нехай d ( s , v ) позначає відстань від s до v .GsvGd(s,v)sv
Тепер визначте графік S таким чином. Він складається з кожного ребра u → v таким, що (1) u → v - це край у G , а (2) d ( s , v ) = d ( s , u ) + w ( u , v ) .Su→vu→vGd(s,v)=d(s,u)+w(u,v)
Графік S має деякі зручні властивості:S
Кожен найкоротший шлях від s до t у G існує як шлях у S : найкоротший шлях s = v 0 , v 1 , v 2 , … , v k = t у G має властивість d ( s , v i + 1 ) = d ( s , v i ) + w ( v i , v istGSs=v0,v1,v2,…,vk=tG+ 1 ), такребро v я → v я + 1 присутня вS.d(s,vi+1)=d(s,vi)+w(vi,vi+1)vi→vi+1S
Кожен шлях в S з S до т є найкоротшим в G . Зокрема, розглянемо будь-який шлях у S від s до t , скажімо, s = v 0 , v 1 , v 2 , … , v k = t . Його довжина визначається сумою ваг його ребер, а саме ∑ k i = 1 w ( v i - 1 , v i )SstGSsts=v0,v1,v2,…,vk=t∑ki=1w(vi−1,vi), але за визначенням S ця сума дорівнює ∑ k i = 1 ( d ( s , v i ) - d ( s , v i - 1 ) , що телескопи до d ( s , t ) - d ( s , s ) = d ( s , t ) . Тому цей шлях - найкоротший шлях від s до t в GS∑ki=1(d(s,vi)−d(s,vi−1)d(s,t)−d(s,s)=d(s,t)stG.
Нарешті, відсутність ребер з нульовою вагою в G означає, що S - даг.GS
Крок 2: вибірка випадкового шляху. Тепер ми можемо викинути ваги по краях в S , і зразок випадкового шляху від ї до т в S .SstS
To help with this, we will do a precomputation to compute n(v)n(v) for each vertex vv in SS, where n(v)n(v) counts the number of distinct paths from vv to tt. This precomputation can be done in linear time by scanning the vertices of SS in topologically sorted order, using the following recurrence relation:
n(v)=∑w∈succ(v)n(w)
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.