日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图的四种最短路径算法

發(fā)布時(shí)間:2023/11/30 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图的四种最短路径算法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文總結(jié)了圖的幾種最短路徑算法的實(shí)現(xiàn):深度或廣度優(yōu)先搜索算法,弗洛伊德算法,迪杰斯特拉算法,Bellman-Ford算法

?

1),深度或廣度優(yōu)先搜索算法(解決單源最短路徑)
從起始結(jié)點(diǎn)開始訪問所有的深度遍歷路徑或廣度優(yōu)先路徑,則到達(dá)終點(diǎn)結(jié)點(diǎn)的路徑有多條,取其中路徑權(quán)值最短的一條則為最短路徑。

下面是核心代碼:

?

[cpp]?view plain?copy

  • void?dfs(int?cur,?int?dst){????
  • ????/***operation***/????
  • ????
  • ????/***operation***/????
  • ????if(minPath?<?dst)?return;//當(dāng)前走過路徑大于之前最短路徑,沒必要再走下去????
  • ????if(cur?==?n){//臨界條件????
  • ????????if(minPath?>?dst)?minPath?=?dst;????
  • ????????return;????
  • ????}????
  • ????else{????
  • ????????int?i;????
  • ????????for(i?=?1;?i?<=?n;?i++){????
  • ????????????if(edge[cur][i]?!=?inf?&&?edge[cur][i]?!=?0?&&?mark[i]?==?0){????
  • ????????????????mark[i]?=?1;????
  • ????????????????dfs(i,?dst+edge[cur][i]);????
  • ????????????????mark[i]?=?0;??//需要在深度遍歷返回時(shí)將訪問標(biāo)志置0??????????????
  • ????????????}????
  • ????????}????
  • ????????return;????
  • ????}????
  • }????
  • 例1:下面是城市的地圖,注意是單向圖,求城市1到城市5的最短距離。(引用的是上次總結(jié)的圖論(一)中1)的例2)

    ?

    [cpp]?view plain?copy

  • /***先輸入n個(gè)結(jié)點(diǎn),m條邊,之后輸入有向圖的m條邊,邊的前兩元素表示起始結(jié)點(diǎn),第三個(gè)值表權(quán)值,輸出1號(hào)城市到n號(hào)城市的最短距離***/????
  • /***算法的思路是訪問所有的深度遍歷路徑,需要在深度遍歷返回時(shí)將訪問標(biāo)志置0***/????
  • #include?<iostream>????
  • #include?<iomanip>????
  • #define?nmax?110????
  • #define?inf?999999999????
  • using?namespace?std;????
  • int?n,?m,?minPath,?edge[nmax][nmax],?mark[nmax];//結(jié)點(diǎn)數(shù),邊數(shù),最小路徑,鄰接矩陣,結(jié)點(diǎn)訪問標(biāo)記????
  • void?dfs(int?cur,?int?dst){????
  • ????/***operation***/????
  • ????
  • ????/***operation***/????
  • ????if(minPath?<?dst)?return;//當(dāng)前走過路徑大于之前最短路徑,沒必要再走下去????
  • ????if(cur?==?n){//臨界條件????
  • ????????if(minPath?>?dst)?minPath?=?dst;????
  • ????????return;????
  • ????}????
  • ????else{????
  • ????????int?i;????
  • ????????for(i?=?1;?i?<=?n;?i++){????
  • ????????????if(edge[cur][i]?!=?inf?&&?edge[cur][i]?!=?0?&&?mark[i]?==?0){????
  • ????????????????mark[i]?=?1;????
  • ????????????????dfs(i,?dst+edge[cur][i]);????
  • ????????????????mark[i]?=?0;????????????????
  • ????????????}????
  • ????????}????
  • ????????return;????
  • ????}????
  • }????
  • ????
  • int?main(){????
  • ????while(cin?>>?n?>>?m?&&?n?!=?0){????
  • ????????//初始化鄰接矩陣????
  • ????????int?i,?j;????
  • ????????for(i?=?1;?i?<=?n;?i++){????
  • ????????????for(j?=?1;?j?<=?n;?j++){????
  • ????????????????edge[i][j]?=?inf;????
  • ????????????}????
  • ????????????edge[i][i]?=?0;????
  • ????????}????
  • ????????int?a,?b;????
  • ????????while(m--){????
  • ????????????cin?>>?a?>>?b;????
  • ????????????cin?>>?edge[a][b];????
  • ????????}????
  • ????????//以dnf(1)為起點(diǎn)開始遞歸遍歷????
  • ????????memset(mark,?0,?sizeof(mark));????
  • ????????minPath?=?inf;????
  • ????????mark[1]?=?1;????
  • ????????dfs(1,?0);????
  • ????????cout?<<?minPath?<<?endl;????
  • ????}????
  • ????return?0;????
  • }????
  • 程序運(yùn)行結(jié)果如下:

    ?

    ?

    2),弗洛伊德算法(解決多源最短路徑):時(shí)間復(fù)雜度O(n^3),空間復(fù)雜度O(n^2)
    基本思想:最開始只允許經(jīng)過1號(hào)頂點(diǎn)進(jìn)行中轉(zhuǎn),接下來只允許經(jīng)過1號(hào)和2號(hào)頂點(diǎn)進(jìn)行中轉(zhuǎn)......允許經(jīng)過1~n號(hào)所有頂點(diǎn)進(jìn)行中轉(zhuǎn),來不斷動(dòng)態(tài)更新任意兩點(diǎn)之間的最短路程。即求從i號(hào)頂點(diǎn)到j(luò)號(hào)頂點(diǎn)只經(jīng)過前k號(hào)點(diǎn)的最短路程。

    分析如下:1,首先構(gòu)建鄰接矩陣Floyd[n+1][n+1],假如現(xiàn)在只允許經(jīng)過1號(hào)結(jié)點(diǎn),求任意兩點(diǎn)間的最短路程,很顯然Floyd[i][j] = min{Floyd[i][j], Floyd[i][1]+Floyd[1][j]},代碼如下:

    ?

    [cpp]?view plain?copy

  • for(i?=?1;?i?<=?n;?i++){??
  • ????for(j?=?1;?j?<=?n;?j++){??
  • ????????if(Floyd[i][j]?>?Floyd[i][1]?+?Floyd[1][j])??
  • ????????????Floyd[i][j]?=?Floyd[i][1]?+?Floyd[1][j];??
  • ????}??
  • }??
  • 2,接下來繼續(xù)求在只允許經(jīng)過1和2號(hào)兩個(gè)頂點(diǎn)的情況下任意兩點(diǎn)之間的最短距離,在已經(jīng)實(shí)現(xiàn)了從i號(hào)頂點(diǎn)到j(luò)號(hào)頂點(diǎn)只經(jīng)過前1號(hào)點(diǎn)的最短路程的前提下,現(xiàn)在再插入第2號(hào)結(jié)點(diǎn),來看看能不能更新更短路徑,故只需在步驟1求得的Floyd[n+1][n+1]基礎(chǔ)上,進(jìn)行Floyd[i][j] = min{Floyd[i][j], Floyd[i][2]+Floyd[2][j]};......
    3,很顯然,需要n次這樣的更新,表示依次插入了1號(hào),2號(hào)......n號(hào)結(jié)點(diǎn),最后求得的Floyd[n+1][n+1]是從i號(hào)頂點(diǎn)到j(luò)號(hào)頂點(diǎn)只經(jīng)過前n號(hào)點(diǎn)的最短路程。故核心代碼如下:

    ?

    [cpp]?view plain?copy

  • #define?inf?99999999??
  • for(k?=?1;?k?<=?n;?k++){??
  • ????for(i?=?1;?i?<=?n;?i++){??
  • ????????for(j?=?1;?j?<=?n;?j++){??
  • ????????????if(Floyd[i][k]?<?inf?&&?Floyd[k][j]?<?inf?&&?Floyd[i][j]?>?Floyd[i][k]?+?Floyd[k][j])??
  • ????????????????Floyd[i][j]?=?Floyd[i][k]?+?Floyd[k][j];??
  • ????????}??
  • ????}??
  • }??
  • 例1:尋找最短的從商店到賽場(chǎng)的路線。其中商店在1號(hào)結(jié)點(diǎn)處,賽場(chǎng)在n號(hào)結(jié)點(diǎn)處,1~n結(jié)點(diǎn)中有m條線路雙向連接。

    ?

    [cpp]?view plain?copy

  • /***先輸入n,m,再輸入m個(gè)三元組,n為路口數(shù),m表示有幾條路其中1為商店,n為賽場(chǎng),三元組分別表起點(diǎn),終點(diǎn),該路徑長(zhǎng),輸出1到n的最短路徑***/??
  • #include?<iostream>??
  • using?namespace?std;??
  • #define?inf?99999999??
  • #define?nmax?110??
  • int?edge[nmax][nmax],?n,?m;??
  • int?main(){??
  • ????while(cin?>>?n?>>?m?&&?n!=?0){??
  • ????????//構(gòu)建鄰接矩陣??
  • ????????int?i,?j;??
  • ????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????for(j?=?1;?j?<=?n;?j++){??
  • ????????????????edge[i][j]?=?inf;??
  • ????????????}??
  • ????????????edge[i][i]?=?0;??
  • ????????}??
  • ????????while(m--){??
  • ????????????cin?>>?i?>>?j;??
  • ????????????cin?>>?edge[i][j];??
  • ????????????edge[j][i]?=?edge[i][j];??
  • ????????}??
  • ????????//使用弗洛伊德算法??
  • ????????int?k;??
  • ????????for(k?=?1;?k?<=?n;?k++){??
  • ????????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????????for(j?=?1;?j?<=?n;?j++){??
  • ????????????????????if(edge[i][k]?<?inf?&&?edge[k][j]?<?inf?&&?edge[i][j]?>?edge[i][k]?+?edge[k][j])??
  • ????????????????????????edge[i][j]?=?edge[i][k]?+?edge[k][j];??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????cout?<<?edge[1][n]?<<?endl;??
  • ????}??
  • ????return?0;??
  • }??
  • 程序運(yùn)行結(jié)果如下:

    ?

    ?

    3),迪杰斯特拉算法(解決單源最短路徑)
    基本思想:每次找到離源點(diǎn)(如1號(hào)結(jié)點(diǎn))最近的一個(gè)頂點(diǎn),然后以該頂點(diǎn)為中心進(jìn)行擴(kuò)展,最終得到源點(diǎn)到其余所有點(diǎn)的最短路徑。
    基本步驟:1,設(shè)置標(biāo)記數(shù)組book[]:將所有的頂點(diǎn)分為兩部分,已知最短路徑的頂點(diǎn)集合P和未知最短路徑的頂點(diǎn)集合Q,很顯然最開始集合P只有源點(diǎn)一個(gè)頂點(diǎn)。book[i]為1表示在集合P中;
    2,設(shè)置最短路徑數(shù)組dst[]并不斷更新:初始狀態(tài)下,令dst[i] = edge[s][i](s為源點(diǎn),edge為鄰接矩陣),很顯然此時(shí)dst[s]=0,book[s]=1。此時(shí),在集合Q中可選擇一個(gè)離源點(diǎn)s最近的頂點(diǎn)u加入到P中。并依據(jù)以u(píng)為新的中心點(diǎn),對(duì)每一條邊進(jìn)行松弛操作(松弛是指由結(jié)點(diǎn)s-->j的途中可以經(jīng)過點(diǎn)u,并令dst[j]=min{dst[j], dst[u]+edge[u][j]}),并令book[u]=1;
    3,在集合Q中再次選擇一個(gè)離源點(diǎn)s最近的頂點(diǎn)v加入到P中。并依據(jù)v為新的中心點(diǎn),對(duì)每一條邊進(jìn)行松弛操作(即dst[j]=min{dst[j], dst[v]+edge[v][j]}),并令book[v]=1;
    4,重復(fù)3,直至集合Q為空。
    以下是圖示:

    核心代碼如下所示:

    ?

    [cpp]?view plain?copy

  • #define?inf?99999999??
  • /***構(gòu)建鄰接矩陣edge[][],且1為源點(diǎn)***/??
  • for(i?=?1;?i?<=?n;?i++)?dst[i]?=?edge[1][s];??
  • for(i?=?1;?i?<=?n;?i++)?book[i]?=?0;??
  • book[1]?=?1;??
  • for(i?=?1;?i?<=?n-1;?i++){??
  • ????//找到離源點(diǎn)最近的頂點(diǎn)u,稱它為新中心點(diǎn)??
  • ????min?=?inf;??
  • ????for(j?=?1;?j?<=?n;?j++){??
  • ????????if(book[j]?==?0?&&?dst[j]?<?min){??
  • ????????????min?=?dst[j];??
  • ????????????u?=?j;??
  • ????????}??
  • ????}??
  • ????book[u]?=?1;??
  • ????//更新最短路徑數(shù)組??
  • ????for(k?=?1;?k?<=?n;?k++){??
  • ????????if(edge[u][k]?<?inf?&&?book[k]?==?0){??
  • ????????????if(dst[k]?>?dst[u]?+?edge[u][k])??
  • ????????????????dst[k]?=?dst[u]?+?edge[u][k];?????????????
  • ????????}??
  • ????}??
  • }??
  • 例1:給你n個(gè)點(diǎn),m條無向邊,每條邊都有長(zhǎng)度d和花費(fèi)p,給你起點(diǎn)s,終點(diǎn)t,要求輸出起點(diǎn)到終點(diǎn)的最短距離及其花費(fèi),如果最短距離有多條路線,則輸出花費(fèi)最少的。
    輸入:輸入n,m,點(diǎn)的編號(hào)是1~n,然后是m行,每行4個(gè)數(shù) a,b,d,p,表示a和b之間有一條邊,且其長(zhǎng)度為d,花費(fèi)為p。最后一行是兩個(gè)數(shù)s,t;起點(diǎn)s,終點(diǎn) t。n和m為 0 時(shí)輸入結(jié)束。(1<n<=1000, 0<m<100000, s != t)
    輸出:輸出一行,有兩個(gè)數(shù), 最短距離及其花費(fèi)。
    分析:由于每條邊有長(zhǎng)度d和花費(fèi)p,最好構(gòu)建邊結(jié)構(gòu)體存放,此外可以使用鄰接鏈表,使用鄰接鏈表時(shí)需要將上面的核心代碼修改幾個(gè)地方:

    1,初始化dst[]時(shí)使用結(jié)點(diǎn)1的鄰接鏈表;
    2,更新最短路徑數(shù)組時(shí),k的范圍由1~n變?yōu)?~edge[u].size()。先采用鄰接矩陣解決此題,再使用鄰接表解決此題,兩種方法的思路都一樣:初始化鄰接矩陣或鄰接鏈表,并
    初始化最短路徑數(shù)組dst ----> n-1輪邊的松弛中,先找到離新源點(diǎn)最近的中心點(diǎn)u,之后根據(jù)中心點(diǎn)u為轉(zhuǎn)折點(diǎn)來更新路徑數(shù)組。

    使用鄰接矩陣求解:

    ?

    [cpp]?view plain?copy

  • /***對(duì)于無向圖,輸入n,m,點(diǎn)的編號(hào)是1~n,然后是m行,每行4個(gè)數(shù)?a,b,d,p,表示a和b之間有一條邊,且其長(zhǎng)度為d,花費(fèi)為p。最后一行是兩個(gè)數(shù)s,t;起點(diǎn)s,終點(diǎn)?t。***/??
  • /***n和m為?0?時(shí)輸入結(jié)束。(1<n<=1000,?0<m<100000,?s?!=?t)?????輸出:輸出一行,有兩個(gè)數(shù),?最短距離及其花費(fèi)。***/??
  • #include?<iostream>??
  • #include?<iomanip>??
  • using?namespace?std;??
  • #define?nmax?1001??
  • #define?inf?99999999??
  • struct?Edge{??
  • ????int?len;??
  • ????int?cost;??
  • };??
  • Edge?edge[nmax][nmax];??
  • int?dst[nmax],?spend[nmax],?book[nmax],?n,?m,?stNode,?enNode;??
  • int?main(){??
  • ????while(cin?>>?n?>>?m?&&?n?!=?0?&&?m?!=?0){??
  • ????????int?a,?b,?i,?j;??
  • ????????//構(gòu)建鄰接矩陣和最短路徑數(shù)組??
  • ????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????for(j?=?1;?j?<=?n;?j++){??
  • ????????????????edge[i][j].cost?=?0;??
  • ????????????????edge[i][j].len?=?inf;??
  • ????????????}??
  • ????????????edge[i][i].len?=?0;??
  • ????????}??
  • ????????while(m--){??
  • ????????????cin?>>?a?>>?b;??
  • ????????????cin?>>?edge[a][b].len?>>?edge[a][b].cost;??
  • ????????????edge[b][a].len?=?edge[a][b].len;??
  • ????????????edge[b][a].cost?=?edge[a][b].cost;??
  • ????????}??
  • ????????cin?>>?stNode?>>?enNode;??
  • ????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????dst[i]?=?edge[stNode][i].len;??
  • ????????????spend[i]?=?edge[stNode][i].cost;??
  • ????????}??
  • ????????memset(book,?0,?sizeof(book));??
  • ????????book[stNode]?=?1;??
  • ????????//開始迪杰斯特拉算法,進(jìn)行剩余n-1次松弛??
  • ????????int?k;??
  • ????????for(k?=?1;?k?<=?n-1;?k++){??
  • ????????????//找離源點(diǎn)最近的頂點(diǎn)u??
  • ????????????int?minNode,?min?=?inf;??
  • ????????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????????if(book[i]?==?0?&&?min?>?dst[i]?/*?||?min?==?dst[i]&&?edge[stNode][min].cost?>?edge[stNode][i].cost*/){??
  • ????????????????????min?=?dst[i];??
  • ????????????????????minNode?=?i;??
  • ????????????????}??
  • ????????????}??
  • ????????????//cout?<<?setw(2)?<<?minNode;??
  • ????????????book[minNode]?=?1;//易錯(cuò)點(diǎn)1,錯(cuò)寫成book[i]=1??
  • ????????????//以中心點(diǎn)u為轉(zhuǎn)折點(diǎn)來更新路徑數(shù)組和花費(fèi)數(shù)組??
  • ????????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????????if(book[i]?==?0?&&?dst[i]?>?dst[minNode]?+?edge[minNode][i].len?||?dst[i]?==?dst[minNode]?+?edge[minNode][i].len?&&?spend[i]?>?spend[minNode]?+?edge[minNode][i].cost){??
  • ????????????????????dst[i]?=?dst[minNode]?+?edge[minNode][i].len;//易錯(cuò)點(diǎn)2,錯(cuò)寫成dst[i]+??
  • ????????????????????spend[i]?=?spend[minNode]?+?edge[minNode][i].cost;??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????cout?<<?dst[enNode]?<<?setw(3)?<<?spend[enNode]?<<?endl;??
  • ????}??
  • ????return?0;??
  • }??
  • 程序運(yùn)行結(jié)果如下:



    使用鄰接鏈表求解:

    ?

    [cpp]?view plain?copy

  • /***對(duì)于無向圖,輸入n,m,點(diǎn)的編號(hào)是1~n,然后是m行,每行4個(gè)數(shù)?a,b,d,p,表示a和b之間有一條邊,且其長(zhǎng)度為d,花費(fèi)為p。最后一行是兩個(gè)數(shù)s,t;起點(diǎn)s,終點(diǎn)?t。***/??
  • /***n和m為?0?時(shí)輸入結(jié)束。(1<n<=1000,?0<m<100000,?s?!=?t)?????輸出:輸出一行,有兩個(gè)數(shù),?最短距離及其花費(fèi)。***/??
  • #include?<iostream>??
  • #include?<iomanip>??
  • #include?<vector>??
  • using?namespace?std;??
  • #define?nmax?1001??
  • #define?inf?99999999??
  • struct?Edge{??
  • ????int?len;??
  • ????int?cost;??
  • ????int?next;??
  • };??
  • vector<Edge>?edge[nmax];??
  • int?dst[nmax],?spend[nmax],?book[nmax],?n,?m,?stNode,?enNode;??
  • int?main(){??
  • ????while(cin?>>?n?>>?m?&&?n?!=?0?&&?m?!=?0){??
  • ????????int?a,?b,?i,?j;??
  • ????????//構(gòu)建鄰接表和最短路徑數(shù)組??
  • ????????for(i?=?1;?i?<=?n;?i++)?edge[i].clear();??
  • ????????while(m--){??
  • ????????????Edge?tmp;??
  • ????????????cin?>>?a?>>?b;??
  • ????????????tmp.next?=?b;??
  • ????????????cin?>>?tmp.len?>>?tmp.cost;??
  • ????????????edge[a].push_back(tmp);??
  • ????????????tmp.next?=?a;??
  • ????????????edge[b].push_back(tmp);??
  • ????????}??
  • ????????cin?>>?stNode?>>?enNode;??
  • ????????for(i?=?1;?i?<=?n;?i++)?dst[i]?=?inf;?//注意2,別忘記寫此句來初始化dst[]??
  • ????????for(i?=?0;?i?<?edge[stNode].size();?i++){//注意1,從下標(biāo)0開始存元素,誤寫成i?<=?edge[stNode].size()??
  • ????????????dst[edge[stNode][i].next]?=?edge[stNode][i].len;??
  • ????????????//cout?<<?dst[2]?<<?endl;??
  • ????????????spend[edge[stNode][i].next]?=?edge[stNode][i].cost;??
  • ????????}??
  • ????????memset(book,?0,?sizeof(book));??
  • ????????book[stNode]?=?1;??
  • ????????//開始迪杰斯特拉算法,進(jìn)行剩余n-1次松弛??
  • ????????int?k;??
  • ????????for(k?=?1;?k?<=?n-1;?k++){??
  • ????????????//找離源點(diǎn)最近的頂點(diǎn)u??
  • ????????????int?minnode,?min?=?inf;??
  • ????????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????????if(book[i]?==?0?&&?min?>?dst[i]?/*?||?min?==?dst[i]&&?edge[stnode][min].cost?>?edge[stnode][i].cost*/){??
  • ????????????????????min?=?dst[i];??
  • ????????????????????minnode?=?i;??
  • ????????????????}??
  • ????????????}??
  • ????????????//cout?<<?setw(2)?<<?minnode;??
  • ????????????book[minnode]?=?1;//易錯(cuò)點(diǎn)1,錯(cuò)寫成book[i]=1??
  • ????????????//以中心點(diǎn)u為轉(zhuǎn)折點(diǎn)來更新路徑數(shù)組和花費(fèi)數(shù)組??
  • ????????????for(i?=?0;?i?<?edge[minnode].size();?i++){??
  • ????????????????int?t?=?edge[minnode][i].next;//別忘了加此句,表示與結(jié)點(diǎn)minnode相鄰的點(diǎn)??
  • ????????????????if(book[t]?==?0?&&?dst[t]?>?dst[minnode]?+?edge[minnode][i].len?||?dst[t]?==?dst[minnode]?+?edge[minnode][i].len?&&?spend[t]?>?spend[minnode]?+?edge[minnode][i].cost){??
  • ????????????????????dst[t]?=?dst[minnode]?+?edge[minnode][i].len;??
  • ????????????????????spend[t]?=?spend[minnode]?+?edge[minnode][i].cost;??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????cout?<<?dst[enNode]?<<?setw(3)?<<?spend[enNode]?<<?endl;??
  • ????}??
  • ????return?0;??
  • }??
  • 程序運(yùn)行結(jié)果如下:


    使用鄰接表時(shí),注意更新dst[],book[]時(shí)要使用鄰接表元素對(duì)應(yīng)下標(biāo)中的next成員,而涉及到權(quán)值加減時(shí)時(shí)需要使用鄰接表中的對(duì)應(yīng)下標(biāo)來取得權(quán)值;而使用鄰接矩陣就沒這么多顧慮了,因?yàn)檫@時(shí)候鄰接矩陣對(duì)應(yīng)下標(biāo)和dst[]要更新元素的下標(biāo)正好一致,都是從1開始編號(hào)。

    ?

    ?

    4),Bellman-Ford算法(解決負(fù)權(quán)邊,解決單源最短路徑,前幾種方法不能求含負(fù)權(quán)邊的圖)::時(shí)間復(fù)雜度O(nm),空間復(fù)雜度O(m)
    主要思想:對(duì)所有的邊進(jìn)行n-1輪松弛操作,因?yàn)樵谝粋€(gè)含有n個(gè)頂點(diǎn)的圖中,任意兩點(diǎn)之間的最短路徑最多包含n-1邊。換句話說,第1輪在對(duì)所有的邊進(jìn)行松弛后,得到的是從1號(hào)頂點(diǎn)只能經(jīng)過一條邊到達(dá)其余各定點(diǎn)的最短路徑長(zhǎng)度。第2輪在對(duì)所有的邊進(jìn)行松弛后,得到的是從1號(hào)頂點(diǎn)只能經(jīng)過兩條邊到達(dá)其余各定點(diǎn)的最短路徑長(zhǎng)度,......
    以下是圖示:

    此外,Bellman_Ford還可以檢測(cè)一個(gè)圖是否含有負(fù)權(quán)回路:如果在進(jìn)行n-1輪松弛后仍然存在dst[e[i]] > dst[s[i]]+w[i]。算法核心代碼如下:

    ?

    [cpp]?view plain?copy

  • #define?inf?999999999??
  • for(i?=?1;?i?<=?n;?i++)?dst[i]?=?inf;??
  • dst[1]?=?0;??
  • for(k?=?1;?k?<=?n-1;?k++){??
  • ????for(i?=?1;?i?<=?m;?i++){??
  • ????????if(dst[e[i]]?>?dst[s[i]]?+?w[i])??
  • ????????????dst[e[i]]?=?dst[s[i]]?+?w[i];??
  • ????}??
  • }??
  • //檢測(cè)負(fù)權(quán)回路??
  • flag?=?0;??
  • for(i?=?1;?i?<=?m;?i++){??
  • ????if(dst[e[i]]?>?dst[s[i]]?+?w[i])??
  • ????????flag?=?1;??
  • }??
  • if(flag)?cout?<<?"此圖含有負(fù)權(quán)回路";??
  • 例1:對(duì)圖示中含負(fù)權(quán)的有向圖,輸出從結(jié)點(diǎn)1到各結(jié)點(diǎn)的最短路徑,并判斷有無負(fù)權(quán)回路。

    ?

    [cpp]?view plain?copy

  • /***先輸入n,m,分別表結(jié)點(diǎn)數(shù)和邊數(shù),之后輸入m個(gè)三元組,各表起點(diǎn),終點(diǎn),邊權(quán),輸出1號(hào)結(jié)點(diǎn)到各結(jié)點(diǎn)的最短路徑****/??
  • #include?<iostream>??
  • #include?<iomanip>??
  • using?namespace?std;??
  • #define?nmax?1001??
  • #define?inf?99999999??
  • int?n,?m,?s[nmax],?e[nmax],?w[nmax],?dst[nmax];??
  • int?main(){??
  • ????while(cin?>>?n?>>?m?&&?n?!=?0?&&?m?!=?0){??
  • ????????int?i,?j;??
  • ????????//初始化三個(gè)數(shù)組:起點(diǎn)數(shù)組s[],終點(diǎn)數(shù)組e[],權(quán)值數(shù)組w[],最短路徑數(shù)組dst[]??
  • ????????for(i?=?1;?i?<=?m;?i++)??
  • ????????????cin?>>?s[i]?>>?e[i]?>>?w[i];??
  • ????????for(i?=?1;?i?<=?n;?i++)??
  • ????????????dst[i]?=?inf;??
  • ????????dst[1]?=?0;??
  • ????????//使用Bellman_Ford算法??
  • ????????for(j?=?1;?j?<=?n-1;?j++){??
  • ????????????for(i?=?1;?i?<=?m;?i++){??
  • ????????????????if(dst[e[i]]?>?dst[s[i]]?+?w[i])??
  • ????????????????????dst[e[i]]?=?dst[s[i]]?+?w[i];??
  • ????????????}??
  • ????????}??
  • ????????//測(cè)試是否有負(fù)權(quán)回路并輸出??
  • ????????int?flag?=?0;??
  • ????????for(i?=?1;?i?<=?m;?i++)??
  • ????????????if(dst[e[i]]?>?dst[s[i]]?+?w[i])??
  • ????????????????flag?=?1;??
  • ????????if(flag)?cout?<<?"此圖含有負(fù)權(quán)回路\n";??
  • ????????else{??
  • ????????????for(i?=?1;?i?<=?n;?i++){??
  • ????????????????if(i?==?1)??
  • ????????????????????cout?<<?dst[i];??
  • ????????????????else???
  • ????????????????????cout?<<?setw(3)?<<?dst[i];??
  • ????????????}??
  • ????????????cout?<<?endl;??
  • ????????}??
  • ????}??
  • ????return?0;??
  • }??
  • 程序運(yùn)行結(jié)果如下:

    總結(jié)

    以上是生活随笔為你收集整理的图的四种最短路径算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。