标签:
package org.loda.graph;
import org.loda.structure.Stack;
import org.loda.util.In;
/**
*
* @ClassName: BellmanFord
* @Description: 最短路径问题
*
* 通用最短路径算法,能解决除了含负权重环以外的所有情况的最短路径,包括了含有负权重边的有向加权图
*
* @author minjun
* @date 2015年5月28日 下午11:04:45
*
*/
public class BellmanFord {
// 原点
private int s;
// 从原点到达i的距离为dist[i]
private double dist[];
// 最短路径的前驱节点
private int[] prev;
// 是否含有负权重环,默认false表示不含有
private boolean negativeCycle;
public BellmanFord(WeightDigraph g, int s) {
int v = g.v();
this.s = s;
dist = new double[v];
prev = new int[v];
for (int i = 0; i < v; i++) {
dist[i] = Double.POSITIVE_INFINITY;
prev[i] = -1;
}
/**
* 由于最短路径一定是一条不含有环的简单路径 1.如果有正环,一定不是最短路径 2.如果是0环,可以去掉改环多余部分也不影响
* 3.如果是负环,则表示不存在最短路径
*
* 简单路径中,数量为V的元素个数形成的最短路径有为V-1个边,对所有边进行V-1次更新,会得到所有点的最短路径
*/
// 不含有负环,所以s->s的最短路径当然为0
dist[s] = 0;
for (int i = 0; i < v - 1; i++) {
for (int m = 0; m < v; m++) {
relax(m, g);
}
}
/**
* 在完成了v-1次全部边更新之后,理应无法继续更新,因为已经找到了s距离每个点的最短路径,如果还能继续更新,说明该图中含有负环。
* 一旦该图含有负环,则表示可以无限次更新下去,也就是说该图根本不存在最短路径
*/
for (int m = 0; m < v; m++) {
for (Edge edge : g.adj(m)) {
int n = edge.otherSide(m);
if (dist[n] > dist[m] + edge.weight()) {
// 含有负权重环
negativeCycle = true;
return;
}
}
}
}
private void relax(int m, WeightDigraph g) {
for (Edge edge : g.adj(m)) {
int n = edge.otherSide(m);
if (dist[n] > dist[m] + edge.weight()) {
dist[n] = dist[m] + edge.weight();
prev[n] = m;
}
}
}
/**
*
* @Title: distTo
* @Description: s->d的最短距离
* @param @param d
* @param @return 设定文件
* @return double 返回类型
* @throws
*/
public double distTo(int d) {
return dist[d];
}
/**
*
* @Title: hasPathTo
* @Description: s->d是否存在可达路径
* @param @param d
* @param @return 设定文件
* @return boolean 返回类型
* @throws
*/
public boolean hasPathTo(int d) {
return distTo(d) < Double.POSITIVE_INFINITY;
}
/**
*
* @Title: pathTo
* @Description: s->d的最短路径
* @param @param d
* @param @return 设定文件
* @return Iterable<Integer> 返回类型
* @throws
*/
public Iterable<Integer> pathTo(int d) {
if (!hasPathTo(d))
return null;
Stack<Integer> path = new Stack<Integer>();
for (int i = d; i != -1; i = prev[i]) {
path.push(i);
}
return path;
}
public static void main(String[] args) {
//不含负权重环的文本数据
String text1="F:\\算法\\attach\\tinyEWDn.txt";
//含有负权重环的文本数据
String text2="F:\\算法\\attach\\tinyEWDnc.txt";
WeightDigraph g = new WeightDigraph(new In(text1
));
BellmanFord d = new BellmanFord(g, 0);
if (d.negativeCycle) {
System.out.println("该有向加权图含有负权重环,不存在最短路径");
} else {
for (int i = 0; i < g.v(); i++) {
Iterable<Integer> path = d.pathTo(i);
if (path == null) {
System.out.println("从原点" + d.s + "到" + i + "没有可达路径");
} else {
System.out.println("从原点" + d.s + "到" + i + "的最短距离为:"
+ d.distTo(i));
System.out.print("路径为:");
for (int j : d.pathTo(i)) {
System.out.print(j + "->");
}
System.out.println();
}
}
}
}
}
上述代码采用text1文本数据的时候,表示该图是不含负权重环的,打印输出的结果为:
从原点0到0的最短距离为:0.0 路径为:0-> 从原点0到1的最短距离为:0.9300000000000002 路径为:0->2->7->3->6->4->5->1-> 从原点0到2的最短距离为:0.26 路径为:0->2-> 从原点0到3的最短距离为:0.9900000000000001 路径为:0->2->7->3-> 从原点0到4的最短距离为:0.26000000000000023 路径为:0->2->7->3->6->4-> 从原点0到5的最短距离为:0.6100000000000002 路径为:0->2->7->3->6->4->5-> 从原点0到6的最短距离为:1.5100000000000002 路径为:0->2->7->3->6-> 从原点0到7的最短距离为:0.6000000000000001 路径为:0->2->7->
打印结果:
该有向加权图含有负权重环,不存在最短路径
标签:
原文地址:http://my.oschina.net/u/1378920/blog/421768