java算法導(dǎo)論之FloydWarshall算法實現(xiàn)代碼
摘要: 算法導(dǎo)論之FloydWarshall算法
求一個圖中任意兩點之間的最短路徑
FloydWarshall算法是通過動態(tài)規(guī)劃來計算任意兩點之間的最短路徑 如果普通求最短路徑,可以對圖進行V次(頂點數(shù))BellmanFord算法。 這樣的話時間復(fù)雜度為EV^2 如果是稀疏圖,則近似于V^3 但是如果是密集圖,則時間復(fù)雜度會近似達到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算法。 這樣的話時間復(fù)雜度為EV^2 * 如果是稀疏圖,則近似于V^3 * 但是如果是密集圖,則時間復(fù)雜度會近似達到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]; // 默認設(shè)置所有節(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 設(shè)定文件 * @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++) { //如果存在使得權(quán)重和更小的中間值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(); } } //檢測負權(quán)重環(huán)的方式很簡單,就是判斷所有i->i的距離d[i][i],如果存在小于0的,表示這個i->i的環(huán)路的權(quán)重和形成了一個負值,也就是存在這個負權(quá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: 是否擁有負權(quán)重環(huán) * @param @return 設(shè)定文件 * @return boolean 返回類型 * @throws */ public boolean hasNegativeCycle() { return negativeCycle; } /** * * @Title: distTo * @Description: a->b最短路徑的距離 * @param @param a * @param @param b * @param @return 設(shè)定文件 * @return double 返回類型 * @throws */ public double distTo(int a, int b) { if (hasNegativeCycle()) throw new RuntimeException("有負權(quán)重環(huán),不存在最短路徑"); return d[a][b]; } /** * * @Title: printShortestPath * @Description: 打印a->b最短路徑 * @param @return 設(shè)定文件 * @return Iterable<Integer> 返回類型 * @throws */ public boolean printShortestPath(int a,int b){ if (hasNegativeCycle()){ System.out.print("有負權(quán)重環(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 設(shè)定文件 * @return void 返回類型 * @throws */ public void addEdge(int a, int b, double w) { d[a][b] = w; } public static void main(String[] args) { // 不含負權(quán)重環(huán)的文本數(shù)據(jù) String text1 = "F:\\算法\\attach\\tinyEWDn.txt"; // 含有負權(quán)重環(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(); } } }
如果采用負權(quán)重環(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
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
- Java算法之?dāng)?shù)組冒泡排序代碼實例講解
- Java算法之串的簡單處理
- Java算法實現(xiàn)調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)之前的講解
- Java算法實現(xiàn)楊輝三角的講解
- Java算法之冒泡排序?qū)嵗a
- Java算法之最長公共子序列問題(LCS)實例分析
- java算法實現(xiàn)紅黑樹完整代碼示例
- Java算法之堆排序代碼示例
- java算法之二分查找法的實例詳解
- java算法實現(xiàn)預(yù)測雙色球中獎號碼
- Java算法之遞歸算法計算階乘
- JAVA算法起步之插入排序?qū)嵗?/a>
- JAVA算法起步之堆排序?qū)嵗?/a>
- JAVA算法起步之快速排序?qū)嵗?/a>
- 關(guān)于各種排列組合java算法實現(xiàn)方法
- Java算法之時間復(fù)雜度和空間復(fù)雜度的概念和計算
相關(guān)文章
JAVA中通過自定義注解進行數(shù)據(jù)驗證的方法
java 自定義注解驗證可自己添加所需要的注解,下面這篇文章主要給大家介紹了關(guān)于JAVA中通過自定義注解進行數(shù)據(jù)驗證的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08Springcloud?feign傳日期類型參數(shù)報錯的解決方案
這篇文章主要介紹了Springcloud?feign傳日期類型參數(shù)報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03Java靜態(tài)內(nèi)部類實現(xiàn)單例過程
這篇文章主要介紹了Java靜態(tài)內(nèi)部類實現(xiàn)單例過程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10Java使用poi實現(xiàn)excel的導(dǎo)入操作指南
使用Apache Poi是一種流行且廣泛使用的方式,可以幫助開發(fā)人員直接從Java代碼中讀取、寫入和處理Excel文件,因此在這篇文章我們將著重介紹如何實現(xiàn)excel的導(dǎo)入,感興趣的朋友可以跟著小編一起來學(xué)習(xí)2023-06-06SpringBoot啟動失敗的解決方法:A component required a&nb
這篇文章主要介紹了解決SpringBoot啟動失?。篈 component required a bean of type ‘xxxxxxx‘ that could not be found.,目前解決方法有兩種,一種是不注入bean的方式,另一種是使用@Component的方式,本文給大家詳細講解,需要的朋友可以參考下2023-02-02基于String和List<String>間的相互轉(zhuǎn)換方式
這篇文章主要介紹了基于String和List間的相互轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05