别说了,世界那么大我想去看看!(最短路径-迪杰斯特拉算法弗洛伊德算法)
前言:
?????一直想去外面的世界看看,中國城市那么多,那么美,怎么樣才可以用最少的錢,最短的時間游遍我想去的城市呢?(我在做夢?不不不!迪杰斯特拉算法和弗洛伊德算法來了)
?????這兩個算法有著廣泛的用途,讓我們來康康:
(***后附代碼演示哦!!!*** )
多么厲害的應用啊,那么讓我們來一起學習吧!
一、迪杰斯特拉算法(Dijkstra)
?????首先說說迪杰斯特拉算法的求解過程:
- 對于網N=(V,E),將N中的頂點分成兩組:
- 第一組 S:已求出的最短路徑的終點集合(初始時只包含源點v0)
- 第二組V-S:尚未求出的最短路徑的頂點集合(初始時為V-{v0})
- 算法將按各頂點與v0間最短路徑長度遞增的次序,逐個將集合V-S中的頂點加入到集合S中去。在這個過程中,總保持v0到集合S中各頂點的路徑長度始終不大于到集合V-S中各頂點的路徑長度。
總結歸納:首先我們知道,這點很重要!
在這條路徑上,必定只含一條邊,并且這條邊是所有從源點v0出發的所有邊中權值最小的一條。那么你想,到其它邊最小的,肯定要經過之前最小的鄰接邊,所以核心思想我們可以說成是依各條最短路徑的長度遞增的次序依次求得各條路徑。
- 下一條路徑長度次短的最短路徑的特點:
- (假設其終點為vk)
- 它只可能有兩種情況:
或者是直接從源點到該頂點的邊: <v0?vk> (只含一條邊);
或者是,從源點經過頂點u,再到達該頂點的兩條邊組成: <v0 ?u> < u ?vk>。- 依次類推:
- 一般情況下,下一條最短路徑的特點: 它或者是直接從源點直達該頂點的一條弧;
或者是,從源點經過已求得了最短路徑的頂點集合中的頂點,再到達該頂點。
算法步驟:
這里需要知道存儲結構一點知識有: 鄰接矩陣G[n][n] (或者鄰接表) 輔助數組: 數組S[n]: 記錄相應頂點是否已求出最短路徑
數組D[n]: 記錄當前所求出的從源點到相應頂點的最短路徑長度 數組Path[n]: 記錄相應頂點路徑中的前驅頂點
(1)初始化:
- 將源點v0加到S中,即S[v0]=true;
- 將v0到各個終點的最短路徑長度初始化為權值,即D[i]=G.arcs[v0][vi],(vi∈V-S);
- 如果v0和頂點vi之間有弧,則將vi的前驅置為v0,即Path[i]=v0,否則Path[i]=-1。
(2)循環n-1次,執行以下操作: - 選擇下一條最短路徑的終點vk,使得:
????D[k]=Min{D[i]|vi∈V-S} - 將vk加到S中,即S[k]=true;
- 根據條件更新從v0出發到集合V-S上任一頂點的最短路徑的長度,若條件D[k]+G.arcs[k][i]<D[i]成立,則更新D[i]=D[k]+G.arcs[k][i],同時更改vi的前驅為vk;Path[i]=k。
為了更好的理解,將上面的總結就是:
1.初始化:先找出從源點v0到各終點vk的直達路徑(v0,vk),即通過一條弧到達的路徑。
2.選擇:從這些路徑中找出一條長度最短的路徑(v0,u)。
3.更新:然后對其余各條路徑進行適當調整:
判斷:若在圖中存在弧(u,vk),且(v0,u)+(u,vk)<(v0,vk),
則以路徑(v0,u,vk)代替(v0,vk)。
在調整后的各條路徑中,再找長度最短的路徑,
依此類推。
看這個例子更好的理解:
求這個圖的最短路徑就有:
二、弗洛伊德算法
?????迪杰斯特拉是從一個點到其余各點的最短路徑,二弗洛伊德則是每對頂點之間的最短路徑。這個時候聰明的你是不是想到調用迪杰斯特拉算法呢?一起來看看趴
?????弗洛伊德算法的基本思想是:
????????????????????從 vi 到 vj 的所有可能存在的路徑中,選出一條長度最短的路徑
算法:
若<vi,vj>存在,則存在路徑{vi,vj}
// 路徑中不含其它頂點
若<vi,v1>,<v1,vj>存在,則存在路徑{vi,v1,vj}
// 路徑中所含頂點序號不大于1
若{vi,…,v2}, {v2,…,vj}存在,
則存在一條路徑{vi, …, v2, …vj}
// 路徑中所含頂點序號不大于2
…
依次類推,則 vi 至 vj 的最短路徑應是上述這些路徑中,路徑長度最小者。
****下面演示代碼:
迪杰斯特拉算法:
演示例子的話可以用上圖哦。
弗洛伊德算法:
//算法 弗洛伊德算法#include <iostream> using namespace std;#define MaxInt 32767 //表示極大值,即∞ #define MVNum 100 //最大頂點數typedef char VerTexType; //假設頂點的數據類型為字符型 typedef int ArcType; //假設邊的權值類型為整型int Path[MVNum][MVNum]; //最短路徑上頂點vj的前一頂點的序號 int D[MVNum][MVNum]; //記錄頂點vi和vj之間的最短路徑長度//------------圖的鄰接矩陣--------------- typedef struct{VerTexType vexs[MVNum]; //頂點表ArcType arcs[MVNum][MVNum]; //鄰接矩陣int vexnum,arcnum; //圖的當前點數和邊數 }AMGraph;int LocateVex(AMGraph G , VerTexType v){//確定點v在G中的位置for(int i = 0; i < G.vexnum; ++i)if(G.vexs[i] == v)return i;return -1; }//LocateVexvoid CreateUDN(AMGraph &G){//采用鄰接矩陣表示法,創建有向網Gint i , j , k;cout <<"請輸入總頂點數,總邊數,以空格隔開:";cin >> G.vexnum >> G.arcnum; //輸入總頂點數,總邊數cout << endl;cout << "輸入點的名稱,如a" << endl;for(i = 0; i < G.vexnum; ++i){cout << "請輸入第" << (i+1) << "個點的名稱:";cin >> G.vexs[i]; //依次輸入點的信息}cout << endl;for(i = 0; i < G.vexnum; ++i){ //初始化鄰接矩陣,邊的權值均置為極大值MaxIntfor(j = 0; j < G.vexnum; ++j){if(j != i)G.arcs[i][j] = MaxInt;elseG.arcs[i][j] = 0;}//for}//forcout << "輸入邊依附的頂點及權值,如a b 3" << endl;for(k = 0; k < G.arcnum;++k){ //構造鄰接矩陣VerTexType v1 , v2;ArcType w;cout << "請輸入第" << (k + 1) << "條邊依附的頂點及權值:";cin >> v1 >> v2 >> w; //輸入一條邊依附的頂點及權值i = LocateVex(G, v1); j = LocateVex(G, v2); //確定v1和v2在G中的位置,即頂點數組的下標G.arcs[i][j] = w; //邊<v1, v2>的權值置為w}//for }//CreateUDNvoid ShortestPath_Floyed(AMGraph G){//用Floyd算法求有向網G中各對頂點i和j之間的最短路徑int i , j , k ;for (i = 0; i < G.vexnum; ++i) //各對結點之間初始已知路徑及距離for(j = 0; j < G.vexnum; ++j){D[i][j] = G.arcs[i][j];if(D[i][j] < MaxInt && i != j) Path[i][j]=i; //如果i和j之間有弧,則將j的前驅置為ielse Path [i][j] = -1; //如果i和j之間無弧,則將j的前驅置為-1}//forfor(k = 0; k < G.vexnum; ++k)for(i = 0; i < G.vexnum; ++i)for(j = 0; j < G.vexnum; ++j)if(D[i][k] + D[k][j] < D[i][j]){ //從i經k到j的一條路徑更短D[i][j] = D[i][k]+D[k][j]; //更新D[i][j]Path[i][j] = Path[k][j]; //更改j的前驅為k}//if }//ShortestPath_Floyedvoid DisplayPath(AMGraph G , int begin ,int temp ){//顯示最短路徑if(Path[begin][temp] != -1){DisplayPath(G , begin ,Path[begin][temp]);cout << G.vexs[Path[begin][temp]] << "-->";} }//DisplayPathint main(){cout << "************弗洛伊德算法**************" << endl << endl;AMGraph G;char start , destination;int num_start , num_destination;CreateUDN(G);cout <<endl;cout << "有向網G創建完成!" << endl;ShortestPath_Floyed(G);cout << "請依次輸入路徑的起點與終點的名稱:";cin >> start >> destination;num_start = LocateVex(G , start);num_destination = LocateVex(G , destination);DisplayPath(G , num_start , num_destination);cout << G.vexs[num_destination] << endl;cout << "最短路徑的長度為:" << D[num_start][num_destination] << endl;cout <<endl;return 0; }//main后記:
?????這里我著重迪杰斯特拉算法,因為弗洛伊德其實本質也是一樣的,如果需要了解更多可以去查閱其它資料哦。
????ps別攔著我,我要去看世界了…竟然沒錢!!哭了,看來巧婦難為無米之炊啊。那么我要去搬磚賺錢啦,期待下一篇博客,沖鴨,搬磚去啦!
總結
以上是生活随笔為你收集整理的别说了,世界那么大我想去看看!(最短路径-迪杰斯特拉算法弗洛伊德算法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于增加小视频(类抖音,快手,微视)模块
- 下一篇: html图片白边的解决方式