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文本數據的時候,表示該圖是不含負權重環的,打印輸出的結果爲: java
從原點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->
打印結果: 算法
該有向加權圖含有負權重環,不存在最短路徑