Dijkstra 的单源最短路径算法能否检测到图中的无限循环?

Posted

技术标签:

【中文标题】Dijkstra 的单源最短路径算法能否检测到图中的无限循环?【英文标题】:Can Dijkstra's Single Source Shortest Path Algorithm detect an infinite cycle in a graph? 【发布时间】:2013-12-06 01:08:15 【问题描述】:

所以我遇到了这个美丽的问题,它要求你编写一个程序来确定有向图中是否存在负无穷最短路径。 (也可以认为是找出图中是否存在“负循环”)。这是问题的链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=499

我通过从图中的任何源开始运行 Bellman Ford 算法两次成功地解决了这个问题。第二次运行算法时,我检查一个节点是否可以放松。如果是这样,那么图中肯定存在负循环。下面是我的 C++ 代码:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int main()

    int test;
    cin>>test;

    for(int T=0; T<test; T++)
    

        int node, E;

        cin>>node>>E; 

        int **edge= new int *[E];
        for(int i=0; i<E; i++)
        
            edge[i]= new int [3];
            cin>>edge[i][0]>>edge[i][1]>>edge[i][2];
        

        int *d= new int [node];

        bool possible=false;

        for(int i=0; i<node;i++)
        
            d[i]= 999999999;
        

        d[node-1]=0;

        for(int i=0; i<node-1; i++)
        

            for(int j=0; j<E; j++)
            
                if(d[edge[j][1]]>d[edge[j][0]]+edge[j][2])
                    d[edge[j][1]]=d[edge[j][0]]+edge[j][2];
            
        

        // time to judge!
        for(int i=0; i<node-1; i++)
        

            for(int j=0; j<E; j++)
            
                if(d[edge[j][1]]>d[edge[j][0]]+edge[j][2])
                
                    possible=true;
                    break;
                

             

            if(possible)
                break;

        

        if(possible)
            cout<<"possible"<<endl;
        else
            cout<<"not possible"<<endl;

    

一位教授曾经告诉我,Dijkstra 的最短路径算法找不到这样的负循环,但他没有证明这一点。我实际上怀疑这种说法。

我的问题是,Dijktstra 的单源最短路径算法可以检测到负循环吗?

当然,我可以尝试 Dijkstra 并检查它是否可行,但我很高兴与您分享这个想法。

【问题讨论】:

无限是什么意思? 对不起,我认为正确的术语是“负循环”。在加权图中,负环是边权重之和为负的环。 【参考方案1】:

您误解了您的教授:他一定说过,如果图中存在 循环,Dijkstra 的算法将不起作用。允许正循环。

该算法不适用于具有负循环的图的原因是此类图中的最短路径未定义:一旦遇到负循环,您可以将“最短路径”的成本降低到您希望的最低值多次跟随负循环。

考虑上面的示例:您从顶点Start 开始,到达A,成本为1。然后你去B,总成本为-1,到C,总成本为-4,现在你可以回到A,总成本为零。通过扩展序列Start-A-B-C-A-B-C-C-A-B-C-...C-...@ @您可以将路径的成本从Start 减少到Finish 到尽可能小的负数。

请注意,负循环限制适用于在图中查找最短路径的所有算法。对 Dijkstra 算法的限制更加严格:它禁止所有的负边。

当然可以修改 Dijkstra 的算法来检测负循环,但这样做没有任何意义,因为你有一个没有负边缘的更严格的限制。

【讨论】:

我同意。这就是他所说的。但是如果图中存在负循环,你能解释为什么 Dijkstra 的算法不起作用吗? 我会检查的。非常感谢。 @Traveling:一旦将节点标记为“已访问”(或“退出”,如this animation),您需要确保这确实是到达该节点的最低成本.如果存在负循环,则存在一个循环,这将导致已处理节点的成本更小。 为什么***说 Dijkstra 的算法适用于非负边(没有提到负循环)?您的意思是您可以将没有负环的图转换为完全没有负边的图吗? @AndreiI 你是对的,如果任何权重为负,Dijkstra 的算法将不起作用。具有负循环的图中未定义最短路径。【参考方案2】:

Dijkstra、Bellman-Ford 和 Floyd-Warshall 都没有算法适用于负循环图,但后两者可以检测到一个,而 Dijkstra 不能,因为 Dijkstra 是贪婪的,而其他算法使用动态规划。此外,Dijkstra 即使没有负循环也不能使用负权重

【讨论】:

以上是关于Dijkstra 的单源最短路径算法能否检测到图中的无限循环?的主要内容,如果未能解决你的问题,请参考以下文章

用小根堆实现dijkstra,求图的单源最短路径

算法入门之单源最短路径算法:Dijkstra(迪杰斯特拉)算法

Dijkstra 的单源最短路径,带有额外的边,权重为“w”

Dijkstra算法求单源最短路径

Dijkstra单源最短路径算法

算法笔记:图论中的单源最短路径算法——Bellman-Ford 算法