标签:
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