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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

图论 —— 最短路 —— Dijkstra 算法

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

【概述】

Dijkstra 算法是單源最短路徑算法,即計(jì)算起點(diǎn)只有一個(gè)的情況到其他點(diǎn)的最短路徑,其無法處理存在負(fù)邊權(quán)的情況。

其時(shí)間復(fù)雜度是:O(E+VlogV)

【算法分析】

將點(diǎn)分為兩類,一類是已確定最短路徑的點(diǎn),稱為:白點(diǎn),一類是未確定最短路徑的點(diǎn),稱為:藍(lán)點(diǎn)。

求一個(gè)點(diǎn)的最短路徑,就是把這個(gè)點(diǎn)由藍(lán)點(diǎn)變?yōu)榘c(diǎn),從起點(diǎn)到藍(lán)點(diǎn)的最短路徑上的中轉(zhuǎn)點(diǎn)在這個(gè)時(shí)刻只能是白點(diǎn)。

Dijkstra 算法的思想,就是一開始將起點(diǎn)到終點(diǎn)的距離標(biāo)記為 0,而后進(jìn)行 n 次循環(huán),每次找出一個(gè)到起點(diǎn)距離 dis[u] 最短的點(diǎn) u ,將它從藍(lán)點(diǎn)變?yōu)榘c(diǎn),隨后枚舉所有白點(diǎn) Vi,如果以此白點(diǎn)為中轉(zhuǎn)到達(dá)藍(lán)點(diǎn) Vi 的路徑 dis[u]+w[u][vi] 更短的話,這將它作為 Vi 的更短路徑(此時(shí)還不能確定是不是Vi的最短路徑)。

以此類推,每找到一個(gè)白點(diǎn),就嘗試用它修改其他所有藍(lán)點(diǎn),中轉(zhuǎn)點(diǎn)先于終點(diǎn)變成白點(diǎn),故每一個(gè)終點(diǎn)一定能被它的最后一個(gè)中轉(zhuǎn)點(diǎn)所修改,從而求得最短路徑。

以下圖為例

算法開始時(shí),作為起點(diǎn)的 dis[1]=0,其他的點(diǎn) dis[i]=0x3f3f3f3f

第一輪循環(huán)找到 dis[1] 最小,將 1 變?yōu)榘c(diǎn),對所有藍(lán)點(diǎn)進(jìn)行修改,使得:dis[2]=2,dis[3]=4,dis[4]=7

此時(shí),dis[2]、dis[3]、dis[4] 被它的最后一個(gè)中轉(zhuǎn)點(diǎn) 1 修改了最短路徑。

第二輪循環(huán)找到 dis[2] 最小,將 2 變成白點(diǎn),對所有藍(lán)點(diǎn)進(jìn)行修改,使得:dis[3]=3、dis[5]=4

此時(shí),dis[3]、dis[5] 被它的最后一個(gè)中轉(zhuǎn)點(diǎn) 2 修改了最短路徑。

第三輪循環(huán)找到 dis[3] 最小,將 3 變成白點(diǎn),對所有藍(lán)點(diǎn)進(jìn)行修改,使得:dis[4]=4。

此時(shí),dis[4] 被它的最后一個(gè)中轉(zhuǎn)點(diǎn) 3 修改了最短路徑,但發(fā)現(xiàn)以 3 為中轉(zhuǎn)不能修改 5,說明 3 不是 5 的最后一個(gè)中轉(zhuǎn)點(diǎn)。

接下來兩輪循環(huán)將 4、5 也變成白點(diǎn)。

N輪循環(huán)結(jié)束,所有點(diǎn)的最短路徑均可求出。

【算法描述】

設(shè)起點(diǎn)為 s,dis[v] 表示從 s 到 v 的最短路徑,pre[v] 為 v 的前驅(qū)結(jié)點(diǎn),vis[v] 用于記錄 v 是否被訪問過。

1.初始化:

dis[v]=0x3f3f3f3f(v≠s),vis[v]=false,即:從始點(diǎn)到各點(diǎn)的值初始化為一極大值,所有點(diǎn)均標(biāo)記為未訪問

dis[s]=0,pre[s]=0,即:始點(diǎn)到始點(diǎn)的距離為 0,且其沒有前驅(qū)結(jié)點(diǎn)

2.算法主體:

for(int i=1;i<=n;i++) {int min=INF;int u=0;for(int v=1;v<=n;v++) { //在沒有被訪問過的點(diǎn)中找一個(gè)頂點(diǎn)u,使得dis[u]是最小的if( vis[v]==false && dis[v]<min) {min=dis[v];u=v;}}if(u==0)break;vis[u]=true;//u標(biāo)記為已確定的最短路徑for(int v=1;j<=n;j++) { //枚舉與u相連的每個(gè)未確定的最短路的頂點(diǎn)if(dis[u]+w[u][v]<dis[v]) {dis[j]=dis[u]+w[u][v]; //更新最短路徑pre[v]=u;//記錄前驅(qū)}} }

3.算法結(jié)束:

dis[v] 即為 s 到 v 最短距離,pre[v] 即為 v 的前驅(qū)結(jié)點(diǎn),用來輸出路徑。

【模版】

1.簡化版

簡化版不可處理重邊圖

int dis[N];//單源最短距離 int G[N][N];//G[i][j]表示i到j(luò)的有向邊長 bool vis[N];//表示w[i]是否已經(jīng)計(jì)算完 void dijkstra(int n,int s){for(int i=1;i<=n;i++){int x;//x標(biāo)記當(dāng)前最短w的點(diǎn)int min_dis=INF;//記錄當(dāng)前最小距離for(int y=1;y<=n;y++){if(!vis[y] && min_dis>=dis[y]){x=y;min_dis=dis[x];}}vis[x]=true;for(int y=1;y<=n;y++) dis[y]=min(dis[y],dis[x]+G[x][y]);} } int main(){memset(dis,INF,sizeof(dis));memset(vis,0,sizeof(vis));int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y,dis;scanf("%d%d%d",&x,&y,&dis);G[x][y] = G[y][x] = dis; //無向圖添邊一次,有向圖添邊兩次}int start;scanf("%d",&start);dijkstra(n,start);for(int i=1;i<=n;i++)printf("%d\n",dis[i]);return 0; }

2.標(biāo)準(zhǔn)版

標(biāo)準(zhǔn)版適用于稀疏圖,可處理重邊圖

int n,m; struct Edge{//邊int from;//邊的起點(diǎn)int to;//邊的終點(diǎn)int dis;//邊的長度Edge(int f,int t,int d){//構(gòu)造函數(shù)from=f;to=t;dis=d;} };struct HeapNode{//Dijkstra用到的優(yōu)先隊(duì)列的結(jié)點(diǎn)int dis;//點(diǎn)到起點(diǎn)距離int u;//點(diǎn)的序號HeapNode(int a,int b){dis=a;u=b;}bool operator < (const HeapNode &rhs) const {return dis > rhs.dis;} };struct Dijkstra{int n,m;//點(diǎn)數(shù)、邊數(shù)vector<Edge> edges;//邊列表vector<int> G[N];//每個(gè)結(jié)點(diǎn)出發(fā)的邊的編號bool vis[N];//是否走過int dis[N];//起點(diǎn)s到各點(diǎn)的距離int p[N];//從起點(diǎn)s到i的最短路中的最后一條邊的編號void init(int n) {//初始化this->n = n;for(int i=0;i<n;i++) //清空鄰接表G[i].clear();edges.clear();//清空邊列表}void AddEdge(int from,int to,int diss) {//添加邊,若為無向圖,調(diào)用兩次edges.push_back(Edge(from,to,diss));m=edges.size();//邊的個(gè)數(shù)G[from].push_back(m-1);//添加至邊列表}int dijkstra(int s) {//求s到所有點(diǎn)的距離memset(dis,INF,sizeof(dis));memset(vis,false,sizeof(vis));dis[s]=0;priority_queue<HeapNode> Q;//優(yōu)先隊(duì)列Q.push(HeapNode(0,s));while(!Q.empty()) {HeapNode x=Q.top();Q.pop();int u=x.u;if(vis[u])//若已被訪問continue;vis[u]=true;//標(biāo)記為已訪問for(int i=0;i<G[u].size();i++) {//枚舉所有與當(dāng)前點(diǎn)相連的邊Edge &e=edges[G[u][i]];if(dis[e.to] > dis[u]+e.dis) {//更新距離dis[e.to] = dis[u]+e.dis;p[e.to]=G[u][i];Q.push(HeapNode(dis[e.to],e.to));}}}return dis[n];//返回起點(diǎn)s到終點(diǎn)n最短距離} }DJ;int main() {while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){DJ.init(n);//初始化for(int i=0;i<m;i++) {int x,y,dis;scanf("%d%d%d",&x,&y,&dis);//無向圖添邊兩次DJ.AddEdge(x,y,dis);DJ.AddEdge(y,x,dis);}int start;scanf("%d",&start);DJ.dijkstra(start);//求start到各點(diǎn)的距離for(int i=0,j=0,s=++start;i<n;i++)//輸出start到各點(diǎn)的距離printf("%d->%d: %d\n",s,++j,DJ.dis[i]);}return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的图论 —— 最短路 —— Dijkstra 算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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