Вот решение, основанное на идеях в ответе Realz Slaw. Это в основном переосмысление его идей, которое может быть более ясным или более легким для понимания. План состоит в том, что мы будем действовать в два этапа:
Сначала мы построим граф со следующим свойством: любой путь от s до t в S является кратчайшим путем от s до t в G , и каждый кратчайший путь из sSstSstGs до в G также присутствует в S . Таким образом, S содержит именно кратчайшие пути в G : все кратчайшие пути и ничего более. Как это бывает, S будет DAG.tGSSGS
Далее, мы будем пробовать равномерно случайным образом из всех путей от до т в S .stS
Этот подход обобщает произвольный ориентированный граф , если все ребра имеют положительный вес, поэтому я объясню свой алгоритм в этих терминах. Пусть w ( u , v ) обозначает вес на ребре u → vGw(u,v)u→v . (Это обобщает постановку задачи, которую вы дали. Если у вас есть невзвешенный граф, просто предположите, что каждое ребро имеет вес 1. Если у вас есть неориентированный граф, обрабатывайте каждое неориентированное ребро как два направленных ребра u → v и v → у .)(u,v)u→vv→u
Шаг 1: экстракт . S Запустите алгоритм кратчайших путей из одного источника (например, алгоритм Дейкстры) на , начиная с источника s . Для каждой вершины v в G пусть d ( s , v ) обозначает расстояние от s до vGsvGd(s,v)sv .
Теперь определим граф следующим образом. Он состоит из каждого ребра u → v такого, что (1) u → v является ребром в G и (2) d (Su→vu→vG .d(s,v)=d(s,u)+w(u,v)
Граф имеет несколько удобных свойств: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. , поэтому ребро v i → v i + 1 присутствует в Sd(s,vi+1)=d(s,vi)+w(vi,vi+1)vi→vi+1S
Каждый путь в из S к т является кратчайшим в G . В частности, рассмотрим любой путь в S от s до t , скажем, s = v 0 , v 1 , v 2 , … , v k = t . Его длина определяется суммой весов его ребер, а именно: ∑ k i = 1 w ( v i - 1 , v iSstGSsts=v0,v1,v2,…,vk=t∑ki=1w(vi−1,vi) , но по определению эта сумма равна ∑ k i = 1 ( d ( sS , который телескопирует к d ( s , t ) - d ( s , s )∑ki=1(d(s,vi)−d(s,vi−1) поэтому этот путь является кратчайшим путем от s до t в.d(s,t)−d(s,s)=d(s,t)stG
Наконец, отсутствие ребер с нулевым весом в означает, что S dag.GS
Шаг 2: выберите случайный путь.Теперь мы можем отбросить веса на ребрах в и выбрать случайный путь от s до t в SSstS .
Чтобы помочь с этим, мы сделаем предварительное вычисление для вычисления для каждой вершины v в S , где nn(v)vS подсчитывает количество различных путей от v до t . Это предварительное вычисление может быть выполнено за линейное время путем сканирования вершин S в топологически отсортированном порядке, используя следующее рекуррентное соотношение:n(v)vtS
n(v)=∑w∈succ(v)n(w)
где обозначает преемников v , т. е. succ ( v ) = { w : v → wsucc(v)v , и где мы имеем базовый случай n ( t ) = 1succ(v)={w:v→w is an edge in S}n(t)=1 .
Далее мы используем аннотацию для выборки случайного пути. Мы первый визит узел sn(⋅)s . Затем мы случайным образом выбираем одного из преемников с преемником w, взвешенным по n ( w ) . Другими словами:swn(w)
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
Чтобы выбрать случайный путь, мы многократно повторяем этот процесс: т.е. и v i + 1 =v0=svi+1= choosesuccessor
. Результирующий путь является желаемым путем, и он будет случайным образом выбран из всех кратчайших путей от s до t.(vi)st .
Надеюсь, это поможет вам легче понять решение Realz Slaw. Вся благодарность Realz Slaw за красивое и чистое решение этой проблемы!
Единственный случай, который не обрабатывается, это случай, когда некоторые ребра имеют вес 0 или отрицательный вес. Тем не менее, в этом случае проблема может быть недостаточно четко определена, поскольку вы можете иметь бесконечно много кратчайших путей.