Dijkstra算法詳解


前言

前幾天研究的Bellman_Ford算法雖然可以算負權,可是時間復雜度高達O(NM),即使是采用了隊列優化,也有可能被網格圖卡回O(NM),所以今天我們就來研究一個新的,更快的,但同時只能在正權圖上運行的算法:Dijkstra(朴素Dijkstra算法)

Dijkstra基本思想及實現過程

我們首先需要以下幾個數組:dist[],vis[],用鄰接矩陣需要g[][],鄰接表則需要v[],w[],head[],nxt[]

鄰接表與鄰接矩陣在此不做過多解釋,不懂的同學請自行百度,dist[i]表示i離源點的最短路距離,vis[i]==1就表示i號節點已經永久標號(之后會詳細解釋什么是永久標號)

算法步驟:

1)將源點距離初始化為0,其它點為正無窮INF

2)經過n次如下操作,得到源點離其它點的最短距離:

1、選擇一個未擴展的點k,滿足dist[k]是未擴展節點中離源點距離最小的;

2、對k進行永久標號

3、以k為中間點修改源點到其它點的最短路距離

時間復雜度O(N2),由於所有邊權都為正,從而保證了算法的正確性。

朴素Dijkstra(鄰接矩陣)

通過上邊的步驟依次實現即可,下面給出參考程序:

Dijkstra堆優化(鄰接表+優先隊列)

 

 1 #include<iostream>
 2 #include<cstring>
 3 #define inf 336860180
 4 using namespace std;
 5 int n,m,x,y,w,map[1000][1000],minn,dist[1000],t;
 6 bool pd[1000];
 7 int main()
 8 {
 9     memset(map,20,sizeof(map));
10     memset(dist,20,sizeof(dist));
11     cin>>n>>m;
12     for(int i=1;i<=n;i++)
13     {
14         map[i][i]=0;
15     }
16     for(int i=1;i<=m;i++)
17     {
18         cin>>x>>y>>w;
19         map[x][y]=w;
20     }
21     dist[1]=0;
22     pd[1]=1;
23     for(int i=1;i<=n;i++)
24     {
25         t=1;minn=9999999;
26         for(int j=1;j<=n;j++)
27         {
28             if(pd[j]==0&&dist[j]<=minn)
29             {
30                 minn=dist[j];
31                 t=j;
32             }
33         }
34         pd[t]=1;
35         for(int j=1;j<=n;j++)
36         {
37             dist[j]=min(dist[j],dist[t]+map[t][j]);
38         }
39     }
40     for(int i=1;i<=n;i++)
41     {
42         if(i-1)cout<<" ";
43         if(dist[i]!=inf)cout<<dist[i];
44         else cout<<"INF";
45     }
46     return 0;
47 }
View Code

 

 

 

由於每次查找最短的點浪費大量時間,我們可以用優先隊列進行查找,用pair記錄,第一維記錄最短距離,第二維記錄點的編號,創建一個小根堆,每次取堆頂擴展即可。時間復雜度降為O((n+m)logm),參考程序如下:

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 using namespace std;
 6 typedef pair<long long,long long>P;
 7 long long n,m,s,dist[100001],v[200005],w[200005],nxt[200005],head[200005],cnt,x,y,z;
 8 bool vis[100001];
 9 void add(long long a,long long b,long long c)
10 {
11     v[++cnt]=b;
12     w[cnt]=c;
13     nxt[cnt]=head[a];
14     head[a]=cnt;
15 }
16 void dijkstra(int s)
17 {
18     memset(dist,20,sizeof(dist));
19     priority_queue<P,vector<P>,greater<P> >q;
20     dist[s]=0;
21     q.push(P(0,s));
22     while(!q.empty())
23     {
24         long long c=q.top().second;
25         q.pop();
26         if(vis[c])continue;
27         vis[c]=1;
28         for(int i=head[c];i;i=nxt[i])
29         {
30             int y=v[i];
31             if(dist[y]>=dist[c]+w[i])
32             {
33                 dist[y]=dist[c]+w[i];
34                 q.push(P(dist[y],y));
35             }
36         }
37     }
38 }
39 int main()
40 {
41     scanf("%d%d%d",&n,&m,&s);
42     for(int i=1;i<=m;i++)
43     {
44         scanf("%d%d%d",&x,&y,&z);
45         add(x,y,z);
46     }
47     dijkstra(s);
48     for(int i=1;i<=n;i++)
49     {
50         cout<<dist[i]<<" ";
51     }
52     return 0;
53 }
View Code

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM