Đây là một giải pháp dựa trên những ý tưởng trong câu trả lời của Realz Slaw. Về cơ bản, nó là một giải trình lại các ý tưởng của anh ta có thể rõ ràng hơn hoặc dễ theo dõi hơn. Kế hoạch là chúng tôi sẽ tiến hành theo hai bước:
Đầu tiên, chúng tôi sẽ xây dựng một đồ thị với các tài sản sau đây: bất kỳ đường đi từ s đến t trong S là một con đường ngắn nhất từ s đến t trong G , và mỗi con đường đi ngắn nhất từ s đến t trong G cũng có mặt trong S . Do đó, S chứa chính xác các đường dẫn ngắn nhất trong G : tất cả các đường dẫn ngắn nhất và không có gì nữa. Khi nó xảy ra, S sẽ là một DAG.SstSstGstGSSGS
Tiếp theo, chúng tôi sẽ lấy mẫu thống nhất một cách ngẫu nhiên từ tất cả các đường dẫn từ đến t trong S .stS
Cách tiếp cận này khái quát hóa cho một đồ thị hướng tùy ý , miễn là tất cả các cạnh có trọng số dương, vì vậy tôi sẽ giải thích thuật toán của mình theo các thuật ngữ đó. Gọi w ( u , v ) biểu thị trọng lượng trên cạnh u → v . (Điều này khái quát hóa tuyên bố vấn đề bạn đã đưa ra. Nếu bạn có một đồ thị không có trọng số, chỉ cần giả sử mọi cạnh đều có trọng số 1. Nếu bạn có một đồ thị vô hướng, hãy coi mỗi cạnh không có hướng ( u , v ) là hai cạnh có hướng u → v và v → u .)Gw(u,v)u→v(u,v)u→vv→u
Bước 1: chiết xuất . S Chạy thuật toán đường dẫn ngắn nhất một nguồn (ví dụ: thuật toán của Dijkstra) trên , bắt đầu từ nguồn s . Với mỗi đỉnh v trong G , hãy để d ( s , v ) biểu thị khoảng cách từ s đến v .GsvGd(s,v)sv
Bây giờ hãy xác định đồ thị như sau. Nó bao gồm mọi cạnh u → v sao cho (1) u → v là một cạnh trong G và (2) d ( s , v ) = d ( s , u ) + w ( u , v ) .Su→vu→vGd(s,v)=d(s,u)+w(u,v)
Biểu đồ có một số thuộc tính thuận tiện:S
Mỗi con đường đi ngắn nhất từ đến t trong G tồn tại như một đường dẫn trong S : một con đường ngắn nhất s = v 0 , v 1 , v 2 , ... , v k = t trong G có tài sản đó d ( s , v i + 1 ) = d ( s , v i ) + w ( v i , v istGSs=v0,v1,v2,…,vk=tG, do đó cạnh v i → v i + 1 có mặt trongS.d(s,vi+1)=d(s,vi)+w(vi,vi+1)vi→vi+1S
Mỗi con đường trong từ s đến t là một con đường ngắn nhất trong G . Đặc biệt, hãy xem xét bất kỳ đường dẫn trong S từ s đến t , nói s = v 0 , v 1 , v 2 , ... , v k = t . Độ dài của nó được tính bằng tổng trọng số của các cạnh của nó, cụ thể là ∑ k i = 1 w ( v i - 1 , v i )SstGSsts=v0,v1,v2,…,vk=t∑ki=1w(vi−1,vi), nhưng theo định nghĩa của , tổng này là ∑ k i = 1 ( d ( s , v i ) - d ( s , v i - 1 ) , mà kính thiên văn cho d ( s , t ) - d ( s , s ) = d ( s , t ) . Do đó, đường dẫn này là đường dẫn ngắn nhất từ s đến t trong GS∑ki=1(d(s,vi)−d(s,vi−1)d(s,t)−d(s,s)=d(s,t)stG.
Cuối cùng, sự vắng mặt của các cạnh có trọng số bằng 0 trong ngụ ý rằng S là một dag.GS
Bước 2: lấy mẫu một đường dẫn ngẫu nhiên. Bây giờ chúng ta có thể vứt bỏ trọng lượng trên các cạnh trong , và lấy mẫu một con đường ngẫu nhiên từ s đến t trong S .SstS
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
v0=svi+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.