所以我遇到了这个美丽的问题,要求你编写一个程序,找出有向图中是否存在负无穷短路径。 (也可以认为是在图中存在“负循环”)。这是问题的链接:
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并检查它是否有效,但我很高兴与你分享这个想法。
答案 0 :(得分:18)
你误解了你的教授:如果图中存在否定周期,他必须说Dijkstra算法不起作用。允许正循环。
算法无法在具有负周期的图形上工作的原因是这些图形中的最短路径未定义:一旦进入负循环,您可以带来“最短路径”的成本。通过多次跟随负循环,尽可能低。
考虑上面的示例:从顶点Start
开始,到达A
,费用为1
。然后,您转到B
,总费用为-1
,转到C
,总共-4
,现在您可以返回A
总成本为零。通过扩展序列Start
- A
- B
- C
- A
- B
- C
- {{1} } - A
- B
-...- C
您可以将路径费用从Finish
降低到Start
,减少到负数。你希望。
请注意,负循环限制适用于在图中查找最短路径的所有算法。对Dijkstra算法的限制甚至更强:它禁止所有负边缘。
当然可以修改Dijkstra的算法来检测负循环,但这样做是没有意义的,因为你对没有负边缘有更强的限制。
答案 1 :(得分:3)
Dijkstra和Bellman-Ford以及Floyd-Warshall都没有算法在负循环图上工作,但后两者可以检测到一个,而Dijkstra不能,因为Dijkstra贪婪而其他人使用动态编程。此外,即使没有负循环,Dijkstra 也不能使用负权重。