算法筆記_006:全源最短路徑問題【動態規划法】


目錄

1 問題描述

2 解決方案

2.1  動態規划法原理簡介

2.2  具體編碼

2.3  運行結果

 

 


1 問題描述

1)實驗題目

   給定一個加權連通圖(無向的或有向的),要求找出從每個定點到其他所有定點之間的最短路徑以及最短路徑的長度。

2)實驗目的

  1)深刻掌握動態規划法的設計思想並能熟練運用,理解它與分治法的區別;

  2)掌握最優性原理和最優子結構性質;

  3)理解這樣一個觀點:用動態規划方法求解問題的關鍵在於確定動態規划函數的遞推式。

3)實驗要求

  1)實現Floyd算法;

  2)算法的輸入可以手動輸入,也可以自動生成;(PS:此處對於有向圖的權重矩陣手動輸入有點麻煩,故本文只實現已給定的權重矩陣值,計算最終結果)

  3)算法不僅要輸出從每個頂點到其他所有頂點之間的最短路徑,還有輸出最短路徑的長度;

  4)設計一個權重為負的圖或有向圖的例子,對於它,Floyd算法不能輸出正確的結果。(PS:在不包含權重和為負數的回路的情況下,可以輸出正確的結果)

 

 


2 解決方案

2.1  動態規划法原理簡介

動態規划算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。動態規划算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解。與分治法不同的是,適合於用動態規划求解的問題,經分解得到子問題往往不是互相獨立的。若用分治法來解這類問題,則分解得到的子問題數目太多,有些子問題被重復計算了很多次。如果我們能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重復計算,節省時間。我們可以用一個表來記錄所有已解的子問題的答案。不管該子問題以后是否被用到,只要它被計算過,就將其結果填入表中。這就是動態規划法的基本思路。具體的動態規划算法多種多樣,但它們具有相同的填表格式

與分治法最大的差別是適合於用動態規划法求解的問題,經分解后得到的子問題往往不是互相獨立的(即下一個子階段的求解是建立在上一個子階段的解的基礎上,進行進一步的求解)

2.2  具體編碼

package com.liuzhen.floyd;

public class Floyd {

    //根據有向圖的權重矩陣及起始的中間節點路徑矩陣,返回最終圖的距離矩陣及中間節點路徑矩陣
    public static void getShortestPath(int[][] chart,int[][] path){
        int len = chart.length;
        for(int k = 0;k < len;k++){  //k = 0表示,增加中間頂點a,k自增,表示后繼增加第k個中間頂點(依次為b,c,d...)
          for(int i = 0;i < len;i++){        
            for(int j = 0;j < len;j++){
int temp = 0; //新增一個中間頂點時,用該變量存儲從i到k再到j的路徑長度 if(chart[i][k] != 100 && chart[k][j] != 100) //當A[i][k]和A[k][j]路徑都可以行走,100表示兩頂點不相通 temp = chart[i][k] + chart[k][j]; if(chart[i][j] > temp && temp != 0) { //如果當前i到j路徑長度(包括無法達到情況)大於以k為中間頂點的路徑時 chart[i][j] = temp; path[i][j] = k+1; //當兩頂點相通,且是最短路徑時,把k+1存入中間節點路徑矩陣path中(PS:0表示i到j之間沒有中間節點,1表示中間節點為a,所以此處為k+1,而不是用k,這樣排除0的情況) } } } } } //根據有向圖的中間節點路徑矩陣,以及兩個頂點,返回這兩個頂點之間的最短路徑 public static String getOneShortestPath(int[][] path,int start,int end){ char startNode = (char) ('a' + start); char endNode = (char) ('a' + end); String nodePath = ""; if(path[start][end] == 0){ nodePath += startNode+"->"+endNode; return nodePath; } int middle = path[start][end]-1; //使用遞歸求解最短路徑 nodePath += getOneShortestPath(path,start,middle)+" , "+getOneShortestPath(path,middle,end); return nodePath; } //輸出有向圖所有頂點之間的最短路徑及最短路徑長度 public static void printShortestPath(int[][] path,int[][] result){ int len = path.length; for(int i = 0;i < len;i++){ char startNode = (char) ('a' + i); for(int j = 0;j < len;j++){ char endNode = (char) ('a' + j); String ijPath = startNode+"——>"+endNode+"最短路徑為:"; String nodePath = getOneShortestPath(path,i,j); System.out.println(ijPath+nodePath+" 。 路徑長度為:"+result[i][j]); } } } public static void main(String args[]){ /*chart數組中,數組0,1,2,3等表示兩頂點之間的權重值,即兩頂點間的距離大小, 100表示兩頂點不相通*/ int[][] chart = {{0,100,3,100},{2,0,100,100},{100,7,0,1},{6,100,100,0}};
System.out.println(
"有向圖chart的權重矩陣為(PS:其中值為100表示無窮大,即無法相通的路徑):"); System.out.println("\t"+"a"+"\t"+"b"+"\t"+"c"+"\t"+"d"); for(int i = 0;i < 4;i++){ char startNode = (char) ('a' + i); System.out.print(startNode+"\t"); for(int j = 0;j < 4;j++) System.out.print(chart[i][j]+"\t"); System.out.println(); } /*path數組中,0表示兩頂點相通,1表示兩頂點間有一個中間節點a,2表示 兩頂點間有一個中間節點b,3兩頂點間有一個中間節點c,4兩頂點間有一個中間節點d. * 100表示兩頂點不相通*/ int[][] path = {{0,100,0,100},{0,0,100,100},{100,0,0,0},{0,100,100,0}}; getShortestPath(chart,path);
System.out.println(
"有向圖chart的距離矩陣為:"); System.out.println("\t"+"a"+"\t"+"b"+"\t"+"c"+"\t"+"d"); for(int i = 0;i < 4;i++){ char startNode = (char) ('a' + i); System.out.print(startNode+"\t"); for(int j = 0;j < 4;j++) System.out.print(chart[i][j]+"\t"); System.out.println(); }
System.out.println(
"有向圖chart的中間節點路徑矩陣為(PS:值為0表示兩節點直接相通,值為1表示兩節點有一個中間節點a,值為2表示中間節點為b,依次類推):"); System.out.println("\t"+"a"+"\t"+"b"+"\t"+"c"+"\t"+"d"); for(int i = 0;i < 4;i++){ char startNode = (char) ('a' + i); System.out.print(startNode+"\t"); for(int j = 0;j < 4;j++) System.out.print(path[i][j]+"\t"); System.out.println(); }
System.out.println(
"最終求取結果為:"); printShortestPath(path,chart); } }

2.3  運行結果

有向圖chart的權重矩陣為(PS:其中值為100表示無窮大,即無法相通的路徑):
    a    b    c    d
a    0    100    3    100    
b    2    0    100    100    
c    100    7    0    1    
d    6    100    100    0    
有向圖chart的距離矩陣為:
    a    b    c    d
a    0    10    3    4    
b    2    0    5    6    
c    7    7    0    1    
d    6    16    9    0    
有向圖chart的中間節點路徑矩陣為(PS:值為0表示兩節點直接相通,值為1表示兩節點有一個中間節點a,值為2表示中間節點為b,依次類推):
    a    b    c    d
a    0    3    0    3    
b    0    0    1    3    
c    4    0    0    0    
d    0    3    1    0    
最終求取結果為:
a——>a最短路徑為:a->a 。 路徑長度為:0
a——>b最短路徑為:a->c , c->b 。 路徑長度為:10
a——>c最短路徑為:a->c 。 路徑長度為:3
a——>d最短路徑為:a->c , c->d 。 路徑長度為:4
b——>a最短路徑為:b->a 。 路徑長度為:2
b——>b最短路徑為:b->b 。 路徑長度為:0
b——>c最短路徑為:b->a , a->c 。 路徑長度為:5
b——>d最短路徑為:b->a , a->c , c->d 。 路徑長度為:6
c——>a最短路徑為:c->d , d->a 。 路徑長度為:7
c——>b最短路徑為:c->b 。 路徑長度為:7
c——>c最短路徑為:c->c 。 路徑長度為:0
c——>d最短路徑為:c->d 。 路徑長度為:1
d——>a最短路徑為:d->a 。 路徑長度為:6
d——>b最短路徑為:d->a , a->c , c->b 。 路徑長度為:16
d——>c最短路徑為:d->a , a->c 。 路徑長度為:9
d——>d最短路徑為:d->d 。 路徑長度為:0

 

參考資料:

      1、http://www.360doc.com/content/13/0601/00/8076359_289597587.shtml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM