再会迪杰斯特拉(Dijkstra)
生活随笔
收集整理的這篇文章主要介紹了
再会迪杰斯特拉(Dijkstra)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
迪杰斯特拉算法
算法說明
迪杰斯特拉算法用來求解某一個起點到以其他所有點為終點的最短路徑長度;
算法思路-貪心算法
以下圖為例
- 指定一個節(jié)點(即起點),例如計算“A”到其他節(jié)點的最短路徑;
- 引入兩個集合(S,U),S集合包含所有已經(jīng)求出其最短路徑的點(以及其最短長度),U集合包括未求出的最短路徑的點;
所有和起點A直接相連的節(jié)點更新其與A的距離為路徑長度,沒有直接相連的設(shè)置為+∞;
- 從U集合中找出距離起點s路徑最短的點,加入S集合,例如第一步最小的為A->D,距離為2;
- 更新U集合路徑,if(A->D+D->(B、C、E))(B、C、E),就更新U;
- 重復執(zhí)行橫線內(nèi)兩步,直到所有的節(jié)點都被加到了集合U中;
下面使用迪杰斯特拉算法處理上圖
①選取起點為A,首先刷新所有和A點直接通過邊相連的點,即B、D點,將A->D置為2,A->B置為4,其他A->C,A->E均為正無窮
算法代碼
#include <stdio.h> #include <iostream> #include <map> #include <stack> #include <vector> #include <queue> #include <algorithm> #include <sstream> #include <cstring> #include <string.h> #include <stdlib.h> #define N 100005 #define INF 2147483647 typedef long long ll; using namespace std; typedef struct Edge {ll to;ll wei;Edge() {to=-1;wei=INF;//初始都為不可達狀態(tài)} } E; ll n,M,s; vector<E>m[N]; //鄰接表 bool wh[N]; //集合U和S,true代表節(jié)點已經(jīng)放入S,false表示還在U集合 ll dis[N]; //存放起點到節(jié)點的最短距離 ll cnt; //S集合元素個數(shù) void Dijkstra(int s) {wh[s]=true;cnt++;while (cnt!=n) {int Min=INF,Minindex=-1;//開始找S集合中距離s最近的節(jié)點for (int i=1; i<=n; i++) {if (!wh[i]&&(dis[i]<Min)) {Min=dis[i];Minindex=i;}}//此時找到了最小的邊//將此節(jié)點放到S集合wh[Minindex]=true;cnt++;//更新U集合路徑for (int i=0; i<m[Minindex].size(); i++) {dis[m[Minindex][i].to]=min(m[Minindex][i].wei+dis[Minindex],dis[m[Minindex][i].to]);}} } int main() {cin>>n>>M>>s;for (int i=1; i<=n; i++) {if(i==s) {dis[s]=0;} else {dis[i]=INF;}}ll f,t,w;for (ll i=1; i<=M; i++) { //存儲圖 cin>>f>>t>>w;int flag=0;//有向圖,不雙向 for (int j=0; j<m[f].size(); j++) { //重邊 if (m[f][j].to==t) {m[f][j].wei=min(w,m[f][j].wei);flag=1;break;}}if (flag==0) {E e;e.to=t;e.wei=w;m[f].push_back(e);}}//找到和起點直接相連的節(jié)點,設(shè)置和起點直接相連的距離for (int i=0; i<m[s].size(); i++) {dis[m[s][i].to]=m[s][i].wei;}Dijkstra(s);for (int i=1; i<=n; i++) {if (i==s) {(i==1)?cout<<0:cout<<" "<<0;continue;}(i==1)?cout<<dis[i]:cout<<" "<<dis[i];} }上述算法即是最樸素的迪杰斯特拉算法,需要注意的是,算法考慮了頂點有重邊的情況,這是洛谷的題目要求的,題目鏈接:
P3371 【模板】單源最短路徑(弱化版)
但對于沒有優(yōu)化的迪杰斯特拉算法,題目的強化版就會直接TLE,分析樸素的Dijkstra算法,我們發(fā)現(xiàn)可以優(yōu)化的點有:
- 每次尋找U集合中dis中最小的元素時使用了遍歷的方法,但我們可以使用小頂堆保證每次直接彈出最小的值,不需要再去遍歷;
對于優(yōu)先隊列,使用stl庫的priority_queue實現(xiàn)。
迪杰斯特拉算法的優(yōu)缺點
- 優(yōu)點
- 算法思路簡單,比較容易上手使用;
- 經(jīng)典的最短路算法,適合大多數(shù)場景;
- 缺點
- 時間復雜度和其他算法相比不太理想,適用于節(jié)點n不太多的情況;
- 不能處理存在總花費為負值且從源點S可達的環(huán)路的圖,因為顯然無限兜圈子花費會越來越小;
- 事實上,存在負環(huán)的情況是抓住了貪心算法的弱點導致問題不能解決;
總結(jié)
以上是生活随笔為你收集整理的再会迪杰斯特拉(Dijkstra)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MYSQL--事务隔离
- 下一篇: 【剑指offer】面试题33:二叉搜索树