Nik*_*nka 5 language-agnostic algorithm graph-theory shortest-path graph-algorithm
此页面中的创意问题34 .
单调最短路径.给定边加权有向图,找到从s到每个其他顶点的单调最短路径.如果路径上每个边缘的权重严格增加或严格减小,则路径是单调的.
部分解决方案:按升序放松边缘,找到最佳路径; 然后按降序放松边缘并找到最佳路径.
我的问题:
假设我们按降序放松边缘,并且我们可以在一个点上选择多于1个边缘.我们将在什么基础上选择下一个优势?理想情况下,我们应该选择较小的边缘,因为它会最小化到该顶点的距离.但是如果离开它的所有边都具有大于当前边的权重的权重,那么这样做可能导致没有来自该顶点的进一步路径.
那么,我们怎样才能解决这个问题呢?
这个问题可以通过修改后的 Dijkstra 算法来解决。主要的一点是放松不应该min在每个图节点(像往常一样)中进行操作,而是在优先级队列中进行。
以下是对常用 Dijkstra 算法的修改列表。我只考虑边缘的升序松弛,这会导致最短路径严格减少(要增加最短路径,请更改第 2 项和第 4 项):
该算法保证每条边最多处理一次(如果我们同时考虑严格递减和严格递增的路径,则最多处理两次),因此其复杂度为 O(E log E)。
C++11 实现:
void getDecreasingSP(Vertices& vertices, Edges& edges, int src)
{
for (auto& v: vertices)
sort(begin(v.outEdges), end(v.outEdges),
[&](int from, int to)
{
return edges[from].weight < edges[to].weight;
});
PQ pq;
auto& src_v = vertices[src];
for (auto e: src_v.outEdges)
{
QEntry entry {edges[e].weight, e};
pq.push(entry);
++src_v.pos;
}
while(!pq.empty())
{
QEntry top = pq.top();
pq.pop();
auto& v = vertices[edges[top.inEdge].to];
while (v.pos < int(v.outEdges.size()) &&
edges[v.outEdges[v.pos]].weight < edges[top.inEdge].weight)
{
auto e = v.outEdges[v.pos];
edges[e].backPtr = top.inEdge;
QEntry entry {top.pathWeight + edges[e].weight, e};
pq.push(entry);
++v.pos;
}
if (v.backPtr == -1)
v.backPtr = top.inEdge;
}
}
Run Code Online (Sandbox Code Playgroud)
另请参阅Ideone 上的工作代码。以及图形的可视化(通过此代码在 Graphviz 的帮助下生成),其中突出显示了严格递减的最短路径之一:
