动态规划实例(十五):最短路径Floyd
? ? 本文參考http://blog.csdn.net/ochangwen/article/details/50730937,
? ? 1.定義概覽
? ? Floyd-Warshall算法(Floyd-Warshall algorithm)又稱為插點(diǎn)法是解決任意兩點(diǎn)間的最短路徑的一種算法,可以正確處理有向圖或負(fù)權(quán)的最短路徑問題,同時(shí)也被用于計(jì)算有向圖的傳遞閉包。Floyd-Warshall算法的時(shí)間復(fù)雜度為O(N3),空間復(fù)雜度為O(N2)。
? ??
? ? 2.算法描述:
? ? 1)算法思想原理:
? ? ?Floyd算法是一個(gè)經(jīng)典的動(dòng)態(tài)規(guī)劃算法。用通俗的語言來描述的話,首先我們的目標(biāo)是尋找從點(diǎn)i到點(diǎn)j的最短路徑。從動(dòng)?態(tài)規(guī)劃的角度看問題,我們需要為這個(gè)目標(biāo)重新做一個(gè)詮釋(這個(gè)詮釋正是動(dòng)態(tài)規(guī)劃最富創(chuàng)造力的精華所在),?從任意節(jié)點(diǎn)i到任意節(jié)點(diǎn)j的最短路徑不外乎2種可能,1是直接從i到j(luò),2是從i經(jīng)過若干個(gè)節(jié)點(diǎn)k到j(luò)。所以,我們假設(shè)
Dis(i,j)為節(jié)點(diǎn)u到節(jié)點(diǎn)v的最短路徑的距離,對于每一個(gè)節(jié)點(diǎn)k,我們檢查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,證明從i到k再到j(luò)的路徑比i直接到j(luò)的路徑
短,我們便設(shè)置Dis(i,j) = Dis(i,k) + Dis(k,j),這樣一來,當(dāng)我們遍歷完所有節(jié)點(diǎn)k,Dis(i,j)中記錄的便是i到j(luò)的最短路徑的距離。
? ? 2).算法描述:
? ? ? ? a.從任意一條單邊路徑開始。所有兩點(diǎn)之間的距離是邊的權(quán),如果兩點(diǎn)之間沒有邊相連,則權(quán)為無窮大。
? ? ? ? b.對于每一對頂點(diǎn) u 和 v,看看是否存在一個(gè)頂點(diǎn) w 使得從 u 到 w 再到 v 比己知的路徑更短。如果是更新它。
? ? 3).Floyd算法過程矩陣的計(jì)算----十字交叉法
? ? ??
? ?補(bǔ)充其中用到的十字交叉法如下:
? ??先來簡單分析下,由于矩陣中對角線上的元素始終為0,因此以k為中間點(diǎn)時(shí),從上一個(gè)矩陣到下一個(gè)矩陣變化時(shí),矩陣的第k行,第k列和對角線上的元素是不發(fā)生改變的(對角線上都是0,因?yàn)橐粋€(gè)頂點(diǎn)到自己的距離就是0,一直不變;而當(dāng)k為中間點(diǎn)時(shí),k到其他頂點(diǎn)(第k行)和其他頂點(diǎn)到k(第k列)的距離是不變的)。
? ? 因此每一步中我們只需要判斷4*4-3*4+2=6個(gè)元素是否發(fā)生改變即可,也就是要判斷既不在第k行第k列又不在對角線上的元素。具體計(jì)算步驟如下:以k為中間點(diǎn)(1)“三條線”:劃去第k行,第k列,對角線(2)“十字交叉法”:對于任一個(gè)不在三條線上的元素x,均可與另外在k行k列上的3個(gè)元素構(gòu)成一個(gè)2階矩陣,x是否發(fā)生改變與2階矩陣中不包含x的那條對角線上2個(gè)元素的和有關(guān),若二者之和小于x,則用它們的和替換x,對應(yīng)的Path矩陣中的與x相對應(yīng)的位置用k來替代。。。
? ? 具體實(shí)例及代碼如下所示:
/** * @Title: Floyd.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-13 上午9:23:39 * @version V1.0 */ package dynamicprogramming; /** * @ClassName: Floyd * @Description: 弗洛伊德最短路徑算法 * @date 2017-6-13 上午9:23:39 * */ public class Floyd {public static void shorestFloyd(){int MAX_VALUE = 65535; int[][] edgesMatrix ={{0, 5, MAX_VALUE, 7}, {MAX_VALUE, 0, 4, 2}, {3, 3, 0, 2}, {MAX_VALUE, MAX_VALUE, 1, 0}}; int n = 4;//vertexSize; 結(jié)點(diǎn)個(gè)數(shù) int[][] tc = new int[n][n]; //保存從i到j(luò)的最短路徑值 int[][] p = new int[n][n]; //保存經(jīng)過的中間結(jié)點(diǎn) //初始化tc,p for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){p[i][j] = -1; tc[i][j] = edgesMatrix[i][j]; //便矩陣 }}//進(jìn)行Floyd算法,從0到n-1所有可能進(jìn)行遍歷 for(int x = 0; x < n; x++){ //x表示中間結(jié)點(diǎn) for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(tc[i][j] > tc[i][x] + tc[x][j]){tc[i][j] = tc[i][x] + tc[x][j]; p[i][j] = x; }}}}// 下面對獲得的結(jié)果進(jìn)行展示 System.out.println("最短路徑狀態(tài)轉(zhuǎn)移矩陣為:"); for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {System.out.print(" " + tc[i][j]); }System.out.println(); }System.out.println("對應(yīng)的結(jié)點(diǎn)矩陣為:"); for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {System.out.print(" " + p[i][j]); }System.out.println(); } // System.out.println("+++++++++++++++++++++++++++++++++++"); /* for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.println("輸出i=" + i + "到j(luò)=" + j + "最短路徑:"); int k = p[i][j]; if (k == -1) { System.out.println("沒有最短路徑"); } else { System.out.print(" " + k); while (k != j) { k = p[k][j]; System.out.print(" " + k); } System.out.println(" "+k); System.out.println(); } } } */ }/** * @Title: main * @Description: 測試用例 * @param args * @return void * @throws */ public static void main(String[] args) {// TODO Auto-generated method stub shorestFloyd(); }}
總結(jié)
以上是生活随笔為你收集整理的动态规划实例(十五):最短路径Floyd的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle vm 介绍,Oracle
- 下一篇: homotopy-同伦_拔剑-浆糊的传说