我正在尝试找出一种算法来查找有向图上的路径。这不是一个传统的路径,我找不到任何像这样的东西的引用。
我想找到具有最大最小重量的路径。
即。如果存在权重为10-> 1-> 10且2-> 2-> 2的两条路径,则认为第二路径优于第一路径,因为最小权重(2)大于最小权重(2)第一个(1)。
如果有人可以找到一种方法来做到这一点,或者只是指向一些参考资料的方向,那将非常有用:)
编辑::我似乎忘了提到我正试图从特定的顶点到另一个特定的顶点。非常重要的一点:/EDIT2 ::如下所述,我应该强调边缘权重是非负的。
答案 0 :(得分:7)
我正在复制this回答并添加我的算法正确性证明:
我会使用Dijkstra's的某些变体。我直接从维基百科中获取了下面的伪代码,只更改了5件小事:
dist
重命名为width
(从第3行开始)width
初始化为-infinity
(第3行)infinity
(第8行)-infinity
(第14行)
1 function Dijkstra(Graph, source):
2 for each vertex v in Graph: // Initializations
3 width[v] := -infinity ; // Unknown width function from
4 // source to v
5 previous[v] := undefined ; // Previous node in optimal path
6 end for // from source
7
8 width[source] := infinity ; // Width from source to source
9 Q := the set of all nodes in Graph ; // All nodes in the graph are
10 // unoptimized – thus are in Q
11 while Q is not empty: // The main loop
12 u := vertex in Q with largest width in width[] ; // Source node in first case
13 remove u from Q ;
14 if width[u] = -infinity:
15 break ; // all remaining vertices are
16 end if // inaccessible from source
17
18 for each neighbor v of u: // where v has not yet been
19 // removed from Q.
20 alt := max(width[v], min(width[u], width_between(u, v))) ;
21 if alt > width[v]: // Relax (u,v,a)
22 width[v] := alt ;
23 previous[v] := u ;
24 decrease-key v in Q; // Reorder v in the Queue
25 end if
26 end for
27 end while
28 return width;
29 endfunction
一些(handwaving)解释为什么这样做:你从源头开始。从那里,你拥有无限的能力。现在检查源的所有邻居。假设边缘不具有相同的容量(在您的示例中,比如(s, a) = 300
)。然后,没有更好的方法可以通过b
到达(s, b)
,因此您知道b
的最佳案例容量。您继续前往已知顶点集的最佳邻居,直到到达所有顶点。
算法正确性证明:
在算法的任何一点,都会有 2组顶点A和B 。 A中的顶点将是找到正确的最大最小容量路径的顶点。并且集合B具有我们尚未找到答案的顶点。
归纳假设:在任何步骤中,集合A中的所有顶点都具有到它们的最大最小容量路径的正确值。即,所有先前的迭代都是正确的。
基本情况的正确性:当集合A仅具有顶点S时。那么S的值是无穷大,这是正确的。
在当前的迭代中,我们设置
val [W] = max(val [W],min(val [V],width_ between(V-W)))
归纳步骤:假设,W是集合B中具有最大val [W]的顶点。并且W从队列中出队并且W已经设置了答案val [W]。
现在,我们需要显示每隔一个S-W路径的宽度 对于集合B中的所有其他顶点X,val [X]< = val [W] 因此,W的任何其他路径都将受到val [X]的约束,它永远不会大于val [W]。 因此val [W]的当前估计是最优的,因此算法计算所有顶点的正确值。
答案 1 :(得分:4)
您还可以使用“答案上的二元搜索”范例。也就是说,对权重进行二元搜索,测试每个权重w
是否可以仅使用权重大于w
的边缘在图表中找到路径。
您可以(通过二分搜索找到)的最大w
给出答案。请注意,您只需检查路径是否存在,因此只需要O(| E |)广度优先/深度优先搜索,而不是最短路径。总而言之,它是O(|E|*log(max W))
,与Dijkstra / Kruskal / Prim的O(|E|log |V|)
相当(我也无法立即看到这些证明)。
答案 2 :(得分:3)
使用Prim's或Kruskal's算法。只需修改它们,以便它们在发现您询问的顶点连接时停止。
编辑:你要求最低限度,但你的例子看起来像你想要的最小值。在最小的情况下,Kruskal的算法将不起作用。
编辑:这个例子没问题,我的错误。只有Prim的算法才有效。答案 3 :(得分:1)
这可以使用BFS样式算法解决,但是您需要两种变体:
例如,如果I和J是邻居,我的值为w1,它们之间的边缘权重为w2,则J = min(w1,w2)。
例如,如果I和J是邻居,则我具有值w1,J具有值w2,并且它们之间的边缘的权重是w3,然后如果min(w2,w3)> w1你必须注意J并再次处理它的所有邻居。
答案 4 :(得分:1)
我不确定Prim会在这里工作。拿这个反例来说:
V = {1, 2, 3, 4}
E = {(1, 2), (2, 3), (1, 4), (4, 2)}
weight function w:
w((1,2)) = .1,
w((2,3)) = .3
w((1,4)) = .2
w((4,2)) = .25
如果你应用Prim来找到1到3的maxmin路径,从1开始将选择1 --> 2 --> 3
路径,而经过4的路径达到最大最小距离。
答案 5 :(得分:0)
好的,在这里回答我自己的问题只是为了尝试获得我在发布之前制定的暂定解决方案的一些反馈:
每个节点都存储一个“路径片段”,这是到目前为止的整个路径。
0)将当前顶点设置为起始顶点
1)从该顶点生成所有路径片段并将它们添加到优先级队列中
2)从优先级队列的顶部取出片段,并将当前顶点设置为该路径的结束顶点
3)如果当前顶点是目标顶点,则返回路径
4)转到1
我不确定这会找到最好的路径,我认为第三步的退出条件有点雄心勃勃。我想不出更好的退出条件,因为这个算法不会关闭顶点(顶点可以在它喜欢的路径片段中引用)你不能等到所有顶点都关闭(就像Dijkstra的例如)
答案 6 :(得分:-1)
你仍然可以使用Dijkstra!
使用min()运算符而不是+ 此外,您还需要确定堆/ priority_queue的方向,以便最重要的事情在最重要的位置。
这样的事情应该有效:(我可能错过了一些实施细节)
let pq = priority queue of <node, minimum edge>, sorted by min. edge descending
push (start, infinity) on queue
mark start as visited
while !queue.empty:
current = pq.top()
pq.pop()
for all neighbors of current.node:
if neighbor has not been visited
pq.decrease_key(neighbor, min(current.weight, edge.weight))
保证无论何时到达节点,您都遵循最佳路径(因为您发现所有可能性按降序排列,并且您永远无法通过添加边缘来改善路径)
时间界限与Dijkstra的相同 - O(Vlog(E))。
编辑:哦等等,这基本上就是你发布的内容。 LOL。