實驗目的
掌握動態規划算法和最短路徑求法,利用最短路徑知識結合實際問題建立數學模型。
實驗要求
實驗步驟要有模型建立,模型求解、結果分析。
實驗內容
(1)某公司在六個城市C1,C2,C3,C4,C5,C6中都有分公司,從Ci到Cj的直達航班票價由下述矩陣的第i行、第j列元素給出(∞表示無直達航班),該公司想算出一張任意兩個城市之間最廉價路線表,試作出這樣的表來
(2)求圖5-28中每一結點到其他結點的最短路
(3)一只狼、一只羊和一筐白菜在河的一岸,一個擺渡人想把它們渡過河去,但是由於他的船很小,每次只能帶走它們之中的一樣,由於明顯的原因,狼和羊或者羊和白菜在一起需要人看守,問擺渡人怎樣把它們渡過河去?
實驗步驟
(1)解:該公司想算出一張任意兩個城市之間最廉價路線表,可把這個路線表抽象成一副帶權的無向圖,於是問題等價於求每對頂點之間最短的問題。本題使用Floyd算法,用MATLAB編程求解
首先,編寫floyd.m文件,代碼如下,

1 %Floyd算法——每對頂點間的最短路徑算法 2 %輸入:帶權鄰接矩陣w(i,j). 3 %輸出:距離矩陣D(i,j),R(i,j) 4 function [d,r]=floyd(w) 5 [m,n]=size(w); 6 if n~=m 7 error('輸入的鄰接矩陣行數不等於列數!!!'); 8 end 9 %預分配內存空間 10 d=zeros(n,n); 11 r=zeros(n,n); 12 %賦初值 13 for i=1:n 14 for j=1:n 15 d(i,j)=w(i,j); 16 r(i,j)=j; 17 end 18 end 19 k=1; 20 %更新d,r 21 while k<=n 22 for i=1:n 23 for j=1:n 24 if d(i,k)+d(k,j)<d(i,j) 25 d(i,j)=d(i,k)+d(k,j); 26 r(i,j)=r(i,k); 27 end 28 end 29 end 30 k=k+1; 31 end 32 end
求解,
為了直觀看出最廉價的線路表,這里編程輸出,

1 % DisplayPath.m 打印路徑函數 2 function DisplayPath(d,r) 3 % 打印出任意兩點之間的最短路徑 4 % route : 路由表 5 % start : 起點index 6 % dest : 終點index 7 [m,n]=size(r); 8 if(n~=m) 9 error('輸入的路徑矩陣有誤!!!'); 10 end 11 for i=1:n 12 for j=i:n 13 if i~=j 14 start=i; 15 dest=j; 16 % fprintf('V%d->V%d\t%d$\t\t',i,j,d(i,j));%例題1 17 fprintf('V%d->V%d\t%d\t\t',i,j,d(i,j)); 18 while 1 19 if(r(start, dest) ~= dest) 20 fprintf('V%s -> ', num2str(start)); 21 start = r(start, dest); 22 else 23 fprintf('V%s -> ', num2str(start)); 24 fprintf('V%s\n', num2str(dest)); 25 break; 26 end 27 end 28 end 29 end 30 end
運行示例,
所以,任意兩城市之間最廉價的線路表如下:
序號 |
始(終) |
終(始) |
線路 |
票價 |
1 |
C1 |
C2 |
1→6→2 |
35 |
2 |
C1 |
C3 |
1→5→3,1→6→4→3 |
45 |
3 |
C1 |
C4 |
1→6→4,1→5→4 |
35 |
4 |
C1 |
C5 |
1→5 |
25 |
5 |
C1 |
C6 |
1→6 |
10 |
6 |
C2 |
C3 |
2→3 |
15 |
7 |
C2 |
C4 |
2→4 |
20 |
8 |
C2 |
C5 |
2→4→5 |
30 |
9 |
C2 |
C6 |
2→6 |
25 |
10 |
C3 |
C4 |
3→4 |
10 |
11 |
C3 |
C5 |
3→4→5,3→5 |
20 |
12 |
C3 |
C6 |
3→4→6 |
35 |
13 |
C4 |
C5 |
4→5 |
10 |
14 |
C4 |
C6 |
4→6 |
25 |
15 |
C5 |
C6 |
5→1→6,5→4→6 |
35 |
(2)解:每一結點到其他結點的最短路,同樣使用Floyd算法,MATLAB求解。解得,
(3)解:設狼:1,菜:2,羊:3,人:4。
方法1:
不安全的組合:13,23,123;題目要求轉移方案為安全,所以同樣不能出現的組合:24,14,4。已知安全的組合:1234,12,34,1,2,3;
人的轉移設定可在河中來回(但是只能搭載一樣),
由上述分析可知,因為河中只能出現2位和1位(當且僅當對岸的組合是12:3時,人才能獨自在河中出現)的組合,第1趟轉移的安全組合:12和34;這兩個組合中只有34有人也就是說,第一趟轉移為:
第二趟轉移的關鍵是當人在回航時如果是獨自回來的話,那么對岸的情況就是13或23,都是不安全狀態,那么只能在回航時帶回羊(3)了(因為不帶回羊的話,只能帶回剛運過去的,這就徒勞無功了)(有兩種情況):
……
只討論左圖的情況(右圖以此類推),顯然第3趟是把1移過對岸(因為3才運回出發點,並且把1移過去是安全的):
顯然,第4趟轉移是把3轉移過去,從而完美解決題目要求:
綜上所述,安全可行(沒有多余的無用功)的轉移方案有兩個,都是4趟轉移:
方案1,第一趟:去(羊人),回(人);第二趟:去(狼人),回(羊人);第三趟:去(菜人),回(人);第四趟:去(羊人)。
方案2,第一趟:去(羊人),回(人);第二趟:去(菜人),回(羊人);第三趟:去(狼人),回(人);第四趟:去(羊人)。
方法2:
由組合學知識,
1位組合:1,2,3,4;
2位組合:12,13,14,23,24,34;
3位組合:123,124,134,234;
4位組合:1234。
其中不允許:123,13,23,4,14,24;因此共有10個允許狀態,轉移關系狀態圖如下,
問題歸結為求頂點1234到頂點0的最短路,將上圖改畫為下面形式:
由上圖可知,有兩種過河方案且等優,如先將羊帶到對岸,再將狼帶到對岸同時把羊帶回原處,將白菜帶到對岸,最后把羊帶過去。
小結
在編寫Floyd程序時,筆者在while循環那里的k值的約束寫成了(k<n),運行之后怎么也得不到筆者想要的結果。筆者數次懷疑自己對路徑矩陣是不是理解錯誤了。於是,筆者回看了路徑矩陣的數學知識,后來實在忍不住筆者就開始一點一點地修改。在修改2個語句后,突然覺得,是不是循環的條件除了問題,果然是的。后來筆者編寫了路徑矩陣的輸出,發現並不能把同一路線的所有情況輸出,可看題1的表,是否有更好的輸出算法呢?
附錄
【1】最短路問題(1) zlc