改进的Bellman-ford算法
本文承接自算法笔记16:单源最短路径
基于队列的Bellman-ford算法的改进:根据前面讲到,对于边e:v→w,只有distTo[v]改变,distTo[w]才会改变,那么我们不需要放松所有边重复V轮,我们只需要放松可能改变的点,例如在下图中,从起点0开始,只有顶点1 2 3才会改变,那么将1 2 3加入队列去放松,其他顶点的不会改变就不会放松。放松1时将4加入队列,依次进行下去直到队列为空。
上图中有负权重边,因为负权重边B的影响,形成了蓝色标出的负权重环:总权重为负的有向环。在存在有向环时队列永远无法为空,会在负权重环中一直走不会出来,负权重环中的顶点的distTo[]会越来越小。同样的因为在负权重环中循环,导致edageTo[]中部分如下
edageTo[2] | edageTo[4] | edageTo[5] |
---|---|---|
C | A | B |
所以当从edageTo中回溯负权重环中的顶点的最短路径和被负权重环隔开的顶点6的时候是回溯不到起点的,只有1和3能回溯到起点,所以此时我们认为只有1和3存在最短路径。由此可以看到应该存在负权重环的判断以在队列永远非空时结束循环,为此根据edageTo[]中的数据建立最短路径树-一个新的加权有向图,然后根据有向环的判定判定是否存在有向环和从起点是否可达以判断是否存在最短路径。有向环和可达性的程序在 有向图中介绍,下面对加权有向图进行适配修改。
mport java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
/**
* 加权有向图的深度优先搜索
* @author XY
*
*/
public class WeightedDiDFS {
private boolean[] marked;
public WeightedDiDFS(EdageWeightedDigraph dgraph,int s) {
marked = new boolean[dgraph.V()];
dfs(dgraph, s);
}
private void dfs(EdageWeightedDigraph dgraph, int s) {
marked[s] = true;
for (WeightedDiEdage e : dgraph.adj(s)){
int x=e.to();
if (!marked[x])
dfs(dgraph, x);
}
}
public boolean marked(int v){
return marked[v];
}
public static void main(String[] args) throws FileNotFoundException {
EdageWeightedDigraph dgraph=new EdageWeightedDigraph(new Scanner
(new File("E:"+File.separator+"wedigraph.txt")));
WeightedDiDFS dfs=new WeightedDiDFS(dgraph, 5);
System.out.println(dfs.marked(7));
}
}
/**
* 加权有向图的有向环判定
* @author XY
*
*/
public class WeightedDiCycle {
private boolean[] marked;
private boolean[] turn;//记录一条路径中已经遍历过的顶点
private boolean hascycle=false;
private Queue