观察:对于每个节点,我们都可以重用它到目的地的最小路径,因此我们不必重新计算它(dp)。另外,一旦发现一个周期,我们就会检查它是否为负。如果不是,它将不会影响我们的最终答案,我们可以说它没有连接到目的地(无论是否连接)。
伪代码:
给出源节点u和目标节点v
初始化整数dp数组,该数组存储到目的节点相对于源节点的最小距离。 dp [v] = 0,其他都是无限的
初始化布尔型onPath数组,该数组存储当前节点是否位于我们正在考虑的路径上。
初始化布尔访问数组,以跟踪当前路径是否已完成(最初全部为false)
初始化存储节点临时值的临时数组。 (暂定[u] = 0)
返回函数(u)。
int function(int node){
onPath[node] = true;
for each connection u of node{
if(onPath[u]){ //we've found a cycle
if(cost to u + tentative[node] > tentative[u]) //report negative cycle
continue; //safely ignore
}
if(visited[u]){
dp[node] = min(dp[node], dp[u]); //dp already calculated
}else{
tentative[u] = tentative[node] + cost to u
dp[node] = min(function(u), dp[node])
}
visited[node] = true;
onPath[node] = false;
return dp[node];
}
我知道该算法无法涵盖目的地是负周期的一部分的情况,但是除此之外,算法有什么问题吗? 如果没有,那叫什么?
答案 0 :(得分:1)
您不能“安全地忽略”正和循环,因为它可能隐藏了一条较短的路径。例如,假设我们有一个带有弧u->x (10), u->y (1), x->y (10), y->x (1), x->v (1), y->v (10)
的图。最短的u-v路径为u->y->x->v
,长度为3。
在执行不佳的情况下,前三个调用看起来像
function(u)
function(x)
function(y)
y
的邻居是v
,产生了长度为10的y->v
路径;和x
,但是循环逻辑禁止考虑该弧,因此y
被标记为以距离10(不是2)访问。结果,我们错过了最短的路径。