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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dijkstra算法图解

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dijkstra算法图解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最短路徑問題

從圖中的某個頂點出發到達另外一個頂點的所經過的邊的權重和最小的一條路徑,稱為最短路徑。

解決方法:

  • Floyd算法
  • Bellman-Ford算法
  • SPFA算法
  • Dijkstra算法

Djikstra算法

算法特點:Dijkstra算法適用于計算正權圖(邊權為正)上的單源最短路,即從單個源點出發,到所有節點的最短路。該算法同時適用于有向圖和無向圖。

算法思路:從已確定最短路徑的節點Vi出發,找到其中權值最小的邊,如果原點到Vi的權值和加Vi到Vj的權值小于已知原點到Vj的權值和,則將原點到Vi的權值和加Vi到Vj的權值作為原點到Vj的最小權和。(講的有點不是特別清楚,看圖分析)

1.已知V1為原點,則從V1出發,找到其中權值最小的邊。即V1到V2這條邊,權值為2,則將V1->V2確定為原點到V2的最短路徑。同時記V1到V3的權值為5,雖然不一定是最短路徑,但要記錄。

2.已確定V1和V2的最短路徑,則V2出發,找到其中權值最小的邊。即V2到V3這條邊,且V1->V2->V3的權值和小于V1->V3的權值,即1+3<5,則將V1->V2->V3確定為原點到V3的最短路徑。同時記V2->V5的權值10,V1->V2->V5的權值和為11,同理雖然不一定為最短路徑,但要記錄。

4已確定V1、V2和V3的最短路徑,則V3出發,找到其中權值最小的邊。即V3到V5這條邊,且V1->V2->V3->V5的權值和為8,小于上一步驟中V1->V2->V5這條路徑。則將V1->B2->V3->V5確定為原點到V5的最短路徑。同時記V1->V2->V3->V4的權值和為11.

5.已確定V1、V2、V3和V5的最短路徑,則從V5出發,找到權值最小的邊。即V5->V4這條邊,且V1->V2->V3->V5->V4的權值和為10,小于上衣步驟中V1->V2->V3->V4這條路徑。則將V1->V2->V3->V5->V4確定為原點到V4的最短路徑。同時記V1->V2->V3->V5->V6的權值和為13.

6.已確定V1、V2、V3、V5和V4的最短路徑,則從V4出發,找到權值最小的邊。即V4->V6這條邊,且V1->V2->V3->V5->V4->V6的權值和為11,小于上一步驟中V1->V2->V3->V5->V6這條路徑。則將V1->V2->V3->V5->V4->V6確定為原點到V6的最短路徑。至此,所有節點的最短路徑都已確定完畢。

為實現這個思路,我們需要定義一個結構體用來存放每一條邊,并且記錄好起點、終點和權值。

struct edge{int from, to, w;//起點,終點,權值 edge(int u, int v, int d){ from=u;to=v;w=d;} }; vector<edge>e[num];//e[i]用于存放以節點i為起點的所有邊。

同時再定義一個結構體用來存放節點編號以及到原點的權值和。

struct node{int id, dist;//節點編號,到原點的距離node(int u, int d){ id=u;dist=d;}bool operator <(const node &a)const{ return dist > a.dist;}//排序規則:按dist從小到大排序 };

?定義三個數組分別記錄每個節點的前驅節點、到原點的權值和、是否已確定為最短路徑。

int pre[num];//前驅節點 int dis[num];//到原點權值和 int done[num];//是否已為最短路徑

?接下來就是最重要的Dijkstra函數的一個實現過程,思路已在前面圖中展現,代碼通過注釋配合圖解應該能夠理解。

鄰接表存圖dijkstra。

#include<iostream> #include<algorithm> #include<queue> #include<vector> using namespace std; const int inf = 0x3f3f3f3f; const int num = 1001;struct edge{int from, to, w;//起點,終點,權值 edge(int u, int v, int d){ from=u;to=v;w=d;} }; vector<edge>e[num];struct node{int id, dist;//節點編號,到原點的距離node(int u, int d){ id=u;dist=d;}bool operator <(const node &a)const{ return dist > a.dist;}//排序規則:按dist從小到大排序 };int n, m, s; int pre[num]; int dis[num]; int done[num]; //分別記錄節點i的前驅節點,到原點的距離,是否已取得最短距離void print_path(int u, int v){//輸出從點u到點v的最短距離路徑 if(u==v){ printf("%d", u);return;}print_path(u, pre[v]);printf("->%d", v); } void dijkstra(){for(int i=1; i<=n; i++){dis[i] = inf;done[i] = 0;}s = 1;dis[s] = 0;priority_queue<node>q;//按dist從小到達排序的優先隊列 q.push(node(s, dis[s]));while(!q.empty()){//取出隊列中的第一個node(含節點編號和距離) node u = q.top();q.pop();if(done[u.id]) continue;//若節點u.id未已取得最短路徑,再執行后續操作 done[u.id] = 1;for(int i=0; i<e[u.id].size(); i++){//遍歷以u.id為起點的所有邊 edge y = e[u.id][i];if(done[y.to]) continue;//若y.to未取得最短路徑,再執行后續操作 if(dis[y.to] > u.dist + y.w){dis[y.to] = u.dist + y.w;q.push(node(y.to, dis[y.to]));pre[y.to] = u.id;}}} }int main(){while(~scanf("%d%d", &n, &m) && n && m){//n個節點,m條邊 for(int i=1; i<=n; i++) e[i].clear();//清空所有邊while(m--){int u, v, w;scanf("%d%d%d", &u, &v, &w);e[u].push_back(edge(u, v, w));e[v].push_back(edge(v, u, w));//(無向圖)將邊分別插入e[u]、e[v] 隊列中 } dijkstra(); }return 0; }

鏈式前向星存圖dijkstra(恢復注釋代碼即hdu1595的解)

#include <iostream> #include <algorithm> #include <queue> using namespace std; const int inf = 0x3f3f3f3f; const int maxm = 1e6; const int maxn = 1006;struct edge{int to, w, next; } e[maxm];struct node{int id, s;node(int a,int b){id = a;s = b;}bool operator <(const node a)const{return a.s < s;} };int n, m, cnt; int id[maxm]; //最短路上經過的邊的序號 int vis[maxn]; //標記數組 int head[maxm]; //鏈式前向星頭結點 int dist[maxn]; //距離數組 int pre[maxn]; //前驅數組 priority_queue<node>q;void addedge(int x,int y,int w){e[cnt].to = y;e[cnt].w = w;e[cnt].next = head[x];head[x] = cnt++; }void clear_set(){for (int i = 1; i <= n; i++)vis[i] = 0;fill(dist, dist + maxn, inf);while(!q.empty())q.pop(); }void init(){cnt = 0;for (int i = 1; i <= n; i++){head[i] = pre[i] = -1;id[i] = 0;} }int dijkstra(int flag,int n){clear_set();dist[1] = 0;q.push(node(1, 0));while(!q.empty()){node p = q.top();q.pop();if(vis[p.id])continue;vis[p.id] = 1;for(int i = head[p.id]; ~i; i = e[i].next){ //head[p.id]訪問的是邊的編號 edge t = e[i];if(!vis[t.to] && dist[t.to] > dist[p.id] + t.w){ //松弛 dist[t.to] = dist[p.id] + t.w;q.push(node(t.to,dist[t.to]));if(flag == 1){ pre[t.to] = p.id; //記錄前驅節點 // id[t.to] = i; //記錄到達這個點的邊的序號 }}}}if(dist[n] == inf)return -1;return dist[n]; }int main(){while(~scanf("%d%d",&n,&m)){init();for(int i = 0; i < m; i++){int x, y, z;scanf("%d%d%d", &x, &y, &z);addedge(x, y, z);addedge(y, x, z);}int ans = dijkstra(1,n);// int t = n;// while(t != -1){ //枚舉最短路經過的所有邊,分別進行一次"刪除"// int w = e[id[t]].w;// e[id[t]].w = inf;// ans = max(ans, dijkstra(0, n));// e[id[t]].w = w; // t = pre[t];// }printf("%d\n",ans);}return 0; }

?

(文末補充,如果有哪里寫的不對或是表述不清的地方,歡迎指出。

總結

以上是生活随笔為你收集整理的Dijkstra算法图解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。