来自this page的广告素材问题34。
单调最短路径。给定边加权有向图,找到从s到每个其他顶点的单调最短路径。如果路径上每条边的权重严格增加或严格减小,则路径是单调的。
部分解决方案:按升序放松边缘并找到最佳路径;然后按降序放松边缘并找到最佳路径。
我的问题:
假设我们按降序放松边缘,并且我们可以在一个点上选择多于1个边缘。我们将在什么基础上选择下一个优势?理想情况下,我们应该选择较小的边缘,因为它会最小化到该顶点的距离。但是,如果离开它的所有边都具有大于当前边缘权重的权重,那么这样做可能导致该顶点没有其他路径。
那么,我们如何解决这个问题?
答案 0 :(得分:4)
这个问题可以通过改进的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;
}
}
另见working code on Ideone。图形的可视化(由此代码在Graphviz的帮助下生成),其中突出显示严格减少的最短路径之一:
答案 1 :(得分:2)
我使用改良的Dijkstra算法来解决它: 例如,如果我们想按升序找到源和其他每个顶点之间的最佳路径,请使用优先级队列PQ:
以权重从i到p放松边缘:
if (disTo[p] > disTo[i] + weight && weight > weight[i, edgeTo[i]) {
disTo[p] = disTo[i] + weight;
edgeTo[p] = i;
PQ.changePriority(p, disTo[p]);
}