Dijkstra算法图解
最短路徑問(wèn)題
從圖中的某個(gè)頂點(diǎn)出發(fā)到達(dá)另外一個(gè)頂點(diǎn)的所經(jīng)過(guò)的邊的權(quán)重和最小的一條路徑,稱(chēng)為最短路徑。
解決方法:
- Floyd算法
- Bellman-Ford算法
- SPFA算法
- Dijkstra算法
Djikstra算法
算法特點(diǎn):Dijkstra算法適用于計(jì)算正權(quán)圖(邊權(quán)為正)上的單源最短路,即從單個(gè)源點(diǎn)出發(fā),到所有節(jié)點(diǎn)的最短路。該算法同時(shí)適用于有向圖和無(wú)向圖。
算法思路:從已確定最短路徑的節(jié)點(diǎn)Vi出發(fā),找到其中權(quán)值最小的邊,如果原點(diǎn)到Vi的權(quán)值和加Vi到Vj的權(quán)值小于已知原點(diǎn)到Vj的權(quán)值和,則將原點(diǎn)到Vi的權(quán)值和加Vi到Vj的權(quán)值作為原點(diǎn)到Vj的最小權(quán)和。(講的有點(diǎn)不是特別清楚,看圖分析)
1.已知V1為原點(diǎn),則從V1出發(fā),找到其中權(quán)值最小的邊。即V1到V2這條邊,權(quán)值為2,則將V1->V2確定為原點(diǎn)到V2的最短路徑。同時(shí)記V1到V3的權(quán)值為5,雖然不一定是最短路徑,但要記錄。
2.已確定V1和V2的最短路徑,則V2出發(fā),找到其中權(quán)值最小的邊。即V2到V3這條邊,且V1->V2->V3的權(quán)值和小于V1->V3的權(quán)值,即1+3<5,則將V1->V2->V3確定為原點(diǎn)到V3的最短路徑。同時(shí)記V2->V5的權(quán)值10,V1->V2->V5的權(quán)值和為11,同理雖然不一定為最短路徑,但要記錄。
4已確定V1、V2和V3的最短路徑,則V3出發(fā),找到其中權(quán)值最小的邊。即V3到V5這條邊,且V1->V2->V3->V5的權(quán)值和為8,小于上一步驟中V1->V2->V5這條路徑。則將V1->B2->V3->V5確定為原點(diǎn)到V5的最短路徑。同時(shí)記V1->V2->V3->V4的權(quán)值和為11.
5.已確定V1、V2、V3和V5的最短路徑,則從V5出發(fā),找到權(quán)值最小的邊。即V5->V4這條邊,且V1->V2->V3->V5->V4的權(quán)值和為10,小于上衣步驟中V1->V2->V3->V4這條路徑。則將V1->V2->V3->V5->V4確定為原點(diǎn)到V4的最短路徑。同時(shí)記V1->V2->V3->V5->V6的權(quán)值和為13.
6.已確定V1、V2、V3、V5和V4的最短路徑,則從V4出發(fā),找到權(quán)值最小的邊。即V4->V6這條邊,且V1->V2->V3->V5->V4->V6的權(quán)值和為11,小于上一步驟中V1->V2->V3->V5->V6這條路徑。則將V1->V2->V3->V5->V4->V6確定為原點(diǎn)到V6的最短路徑。至此,所有節(jié)點(diǎn)的最短路徑都已確定完畢。
為實(shí)現(xiàn)這個(gè)思路,我們需要定義一個(gè)結(jié)構(gòu)體用來(lái)存放每一條邊,并且記錄好起點(diǎn)、終點(diǎn)和權(quán)值。
struct edge{int from, to, w;//起點(diǎn),終點(diǎn),權(quán)值 edge(int u, int v, int d){ from=u;to=v;w=d;} }; vector<edge>e[num];//e[i]用于存放以節(jié)點(diǎn)i為起點(diǎn)的所有邊。同時(shí)再定義一個(gè)結(jié)構(gòu)體用來(lái)存放節(jié)點(diǎn)編號(hào)以及到原點(diǎn)的權(quán)值和。
struct node{int id, dist;//節(jié)點(diǎn)編號(hào),到原點(diǎn)的距離node(int u, int d){ id=u;dist=d;}bool operator <(const node &a)const{ return dist > a.dist;}//排序規(guī)則:按dist從小到大排序 };?定義三個(gè)數(shù)組分別記錄每個(gè)節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)、到原點(diǎn)的權(quán)值和、是否已確定為最短路徑。
int pre[num];//前驅(qū)節(jié)點(diǎn) int dis[num];//到原點(diǎn)權(quán)值和 int done[num];//是否已為最短路徑?接下來(lái)就是最重要的Dijkstra函數(shù)的一個(gè)實(shí)現(xiàn)過(guò)程,思路已在前面圖中展現(xiàn),代碼通過(guò)注釋配合圖解應(yīng)該能夠理解。
鄰接表存圖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;//起點(diǎn),終點(diǎn),權(quán)值 edge(int u, int v, int d){ from=u;to=v;w=d;} }; vector<edge>e[num];struct node{int id, dist;//節(jié)點(diǎn)編號(hào),到原點(diǎn)的距離node(int u, int d){ id=u;dist=d;}bool operator <(const node &a)const{ return dist > a.dist;}//排序規(guī)則:按dist從小到大排序 };int n, m, s; int pre[num]; int dis[num]; int done[num]; //分別記錄節(jié)點(diǎn)i的前驅(qū)節(jié)點(diǎn),到原點(diǎn)的距離,是否已取得最短距離void print_path(int u, int v){//輸出從點(diǎn)u到點(diǎn)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從小到達(dá)排序的優(yōu)先隊(duì)列 q.push(node(s, dis[s]));while(!q.empty()){//取出隊(duì)列中的第一個(gè)node(含節(jié)點(diǎn)編號(hào)和距離) node u = q.top();q.pop();if(done[u.id]) continue;//若節(jié)點(diǎn)u.id未已取得最短路徑,再執(zhí)行后續(xù)操作 done[u.id] = 1;for(int i=0; i<e[u.id].size(); i++){//遍歷以u(píng).id為起點(diǎn)的所有邊 edge y = e[u.id][i];if(done[y.to]) continue;//若y.to未取得最短路徑,再執(zhí)行后續(xù)操作 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個(gè)節(jié)點(diǎ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));//(無(wú)向圖)將邊分別插入e[u]、e[v] 隊(duì)列中 } dijkstra(); }return 0; }鏈?zhǔn)角跋蛐谴鎴Ddijkstra(恢復(fù)注釋代碼即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]; //最短路上經(jīng)過(guò)的邊的序號(hào) int vis[maxn]; //標(biāo)記數(shù)組 int head[maxm]; //鏈?zhǔn)角跋蛐穷^結(jié)點(diǎn) int dist[maxn]; //距離數(shù)組 int pre[maxn]; //前驅(qū)數(shù)組 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]訪問(wèn)的是邊的編號(hào) 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; //記錄前驅(qū)節(jié)點(diǎn) // id[t.to] = i; //記錄到達(dá)這個(gè)點(diǎn)的邊的序號(hào) }}}}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){ //枚舉最短路經(jīng)過(guò)的所有邊,分別進(jìn)行一次"刪除"// 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; }?
(文末補(bǔ)充,如果有哪里寫(xiě)的不對(duì)或是表述不清的地方,歡迎指出。
總結(jié)
以上是生活随笔為你收集整理的Dijkstra算法图解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 让struts2和servlet共存
- 下一篇: java long double精度丢失