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