溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

FloydWarshall算法如何在java項目中實現(xiàn)

發(fā)布時間:2020-11-19 16:19:52 來源:億速云 閱讀:156 作者:Leah 欄目:編程語言

這期內(nèi)容當中小編將會給大家?guī)碛嘘PFloydWarshall算法如何在java項目中實現(xiàn),文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

求一個圖中任意兩點之間的最短路徑  

    FloydWarshall算法是通過動態(tài)規(guī)劃來計算任意兩點之間的最短路徑 

        如果普通求最短路徑,可以對圖進行V次(頂點數(shù))BellmanFord算法。 這樣的話時間復雜度為EV^2
        如果是稀疏圖,則近似于V^3
        但是如果是密集圖,則時間復雜度會近似達到V^4,這種情況需要優(yōu)化,這里FloydWarshall通過動態(tài)規(guī)劃進行優(yōu)化
        ,并且使用鄰接矩陣來表示圖。

實例代碼:

package org.loda.graph;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.loda.util.In;

/**
 * 
 * @ClassName: FloydWarshall
 * @Description: 求一個圖中任意兩點之間的最短路徑
 * 
 *        FloydWarshall算法是通過動態(tài)規(guī)劃來計算任意兩點之間的最短路徑
 * 
 *        如果普通求最短路徑,可以對圖進行V次(頂點數(shù))BellmanFord算法。 這樣的話時間復雜度為EV^2
 *        如果是稀疏圖,則近似于V^3
 *        但是如果是密集圖,則時間復雜度會近似達到V^4,這種情況需要優(yōu)化,這里FloydWarshall通過動態(tài)規(guī)劃進行優(yōu)化
 *        ,并且使用鄰接矩陣來表示圖。 
 *         d(i,j); if m=0 
 *        D(i,j,m)={
 *         min(D(i,m,m-1)+D(m,j,m-1),D(i,j,m-1)); if m!=0
 * @author minjun
 * @date 2015年6月1日 上午9:39:42
 * 
 */
public class FloydWarshall {

 private double[][] d;

 private int[][] prev;

 private int v;

 private boolean negativeCycle;

 public FloydWarshall(int v) {
 this.v = v;

 d = new double[v][v];

 prev = new int[v][v];

 // 默認設置所有節(jié)點都不可達,而自己到自己是可達并且距離為0.0
 for (int i = 0; i < v; i++) {
  for (int j = 0; j < v; j++) {
  d[i][j] = Double.POSITIVE_INFINITY;
  prev[i][j] = -1;
  if(i==j){
   d[i][j] = 0;
  }
  }
 }
 }

 /**
 * 
 * @Title: findShortestPath
 * @Description: 查詢最短路徑
 * @param 設定文件
 * @return void 返回類型
 * @throws
 */
 public void findShortestPath() {
 //查找最短路徑
 for (int k = 0; k < v; k++) {
  //將每個k值考慮成i->j路徑中的一個中間點
  for (int i = 0; i < v; i++) {
  for (int j = 0; j < v; j++) {
   //如果存在使得權重和更小的中間值k,就更新最短路徑為經(jīng)過k的路徑
   if (d[i][j] > d[i][k] + d[k][j]) {
   d[i][j] = d[i][k] + d[k][j];
   prev[i][j]=k;
   }
  }
  }
 }

 //四舍五入距離
 for (int i = 0; i < v; i++) {
  for (int j = 0; j < v; j++) {
  d[i][j] = new BigDecimal(d[i][j]).setScale(2,
   RoundingMode.HALF_UP).doubleValue();
  }
 }

 //檢測負權重環(huán)的方式很簡單,就是判斷所有i->i的距離d[i][i],如果存在小于0的,表示這個i->i的環(huán)路的權重和形成了一個負值,也就是存在這個負權重
 //在之前的其他最短路徑算法中,無法通過這個方法來檢測負環(huán),因為之前路徑距離都是保存在一個一維數(shù)組中,相等于只能檢測d[0][0],無法檢測每個d[i][i]
 for(int i=0;i<v;i++){
  if(d[i][i]<0)
  negativeCycle=true;
 }
 }

 /**
 * 
 * @Title: hasNegativeCycle
 * @Description: 是否擁有負權重環(huán)
 * @param @return 設定文件
 * @return boolean 返回類型
 * @throws
 */
 public boolean hasNegativeCycle() {
 return negativeCycle;
 }

 /**
 * 
 * @Title: distTo
 * @Description: a->b最短路徑的距離
 * @param @param a
 * @param @param b
 * @param @return 設定文件
 * @return double 返回類型
 * @throws
 */
 public double distTo(int a, int b) {
 if (hasNegativeCycle())
  throw new RuntimeException("有負權重環(huán),不存在最短路徑");
 return d[a][b];
 }
 
 /**
 * 
 * @Title: printShortestPath
 * @Description: 打印a->b最短路徑
 * @param @return 設定文件
 * @return Iterable<Integer> 返回類型
 * @throws
 */
 public boolean printShortestPath(int a,int b){
 if (hasNegativeCycle()){
  System.out.print("有負權重環(huán),不存在最短路徑");
 }else if(a==b)
  System.out.println(a+"->"+b);
 else{
  System.out.print(a+"->");
  path(a,b);
  System.out.print(b);
 }
 return true;
 }

 private void path(int a, int b) {
 int k=prev[a][b];
 
 if(k==-1){
  return;
 }
 
 path(a,k);
 System.out.print(k+"->");
 path(k,b);
 }
 
 

 /**
 * 
 * @Title: addEdge
 * @Description: 添加邊
 * @param @param a
 * @param @param b
 * @param @param w 設定文件
 * @return void 返回類型
 * @throws
 */
 public void addEdge(int a, int b, double w) {
 d[a][b] = w;
 }

 public static void main(String[] args) {
 // 不含負權重環(huán)的文本數(shù)據(jù)
 String text1 = "F:\\算法\\attach\\tinyEWDn.txt";
 // 含有負權重環(huán)的文本數(shù)據(jù)
 String text2 = "F:\\算法\\attach\\tinyEWDnc.txt";

 In in = new In(text1);

 int n = in.readInt();
 FloydWarshall f = new FloydWarshall(n);

 int e = in.readInt();

 for (int i = 0; i < e; i++) {
  f.addEdge(in.readInt(), in.readInt(), in.readDouble());
 }

 f.findShortestPath();

 int s = 0;
 for (int i = 0; i < n; i++) {
  System.out.println(s + "到" + i + "的距離為:" + f.distTo(s, i));
  f.printShortestPath(s, i);
  System.out.println();
 }
 }

}

如果采用負權重環(huán)圖,則會拋出異常,提示負環(huán)并表示無最短路徑

如果采用不含負環(huán)的圖,則會打印如下內(nèi)容(目前以s=0作測試,其他點作為原點的最短路徑可以自行嘗試):

0到0的距離為:0.0
0->0

0到1的距離為:0.93
0->2->7->3->6->4->5->1
0到2的距離為:0.26
0->2
0到3的距離為:0.99
0->2->7->3
0到4的距離為:0.26
0->2->7->3->6->4
0到5的距離為:0.61
0->2->7->3->6->4->5
0到6的距離為:1.51
0->2->7->3->6
0到7的距離為:0.6
0->2->7

上述就是小編為大家分享的FloydWarshall算法如何在java項目中實現(xiàn)了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI