1. 程式人生 > 其它 >堆優化Dijkstra演算法

堆優化Dijkstra演算法

但是,我們會發現剛剛講的樸素Dijkstra演算法(高情商:樸素 ; 低情商: 低效)的套路不適用於稀疏圖,很容易會爆時間;

 

所以,我們要對其中的一些操作進行優化,首先我們發現找到裡起始點最近的點去更新其他的點的時候是O(n)的,又因為是稀疏圖我們不能用鄰接矩陣來儲存,所以我們就會想到用鄰接表來儲存,那麼我們在找能更新的位置時,我們就會根據鄰接表的單鏈表進行儲存,把更新後的點放入堆中,這樣的時間複雜度是O(mlogn)的;

 

然後最複雜的地方是,我們再用樸素的 Dijkstra演算法查詢到起始點的最近距離的時候我們用了O(n^2)的時間複雜度,我們要把這裡給優化是效果最好的,所以我們引入了堆(近似完全二叉樹 || 優先佇列:聰明的人都知道用STL,誰還笨笨的手寫堆啊!!!),我們從起始點開始push進堆中,然後每個更新的點我們也都放入堆中,因為這個堆能自動的維護大小順序,我們一開始先定義為一個小根堆,然後每次取堆頂並出堆,就完成了找到裡起始點最近的點的目的;

 

同樣的,對於每個節點我們都要用一個st陣列來標記,因為我們既然訪問到他了,那麼他一定是當前離起始點最近的點,我們就可以大膽的將其設為true(st值)!

 

程式碼:

#include<bits/stdc++.h>
#define x first
#define y second
#define maxn 150010

using namespace std;
typedef pair<int, int> PII;

int h[maxn],e[maxn],w[maxn],ne[maxn],idx,n,m,dist[maxn];
bool st[maxn];

void add(int a, int b, int c)


{
e[idx] = b; w[idx] = c; ne[idx] = h[a] ; h[a] = idx++;
}

int dijkstra(){
memset(dist , 0x3f,sizeof(dist));
priority_queue<PII , vector<PII> , greater<PII> > heap;
PII start;
start.x = 0 ; start.y = 1;
heap.push(start);
while(heap.size()){
PII t = heap.top();


heap.pop();
int ver = t.y , distance = t.x;
if(st[ver]) continue;
st[ver] = true;

for(int i = h[ver] ; i!=-1 ; i = ne[i]){
int j = e[i];
if(dist[j] > distance + w[i]){
dist[j] = distance + w[i];
PII mid;
mid.x = dist[j] ;mid.y = j;
heap.push(mid);
}

}
}
if(dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}

int main()
{
memset(h,-1,sizeof(h));
cin >> n >> m;
for(int i = 1;i<=m;i++){
int a,b,c;
cin >> a >> b >> c;
add(a, b, c);
}
int ans = dijkstra();
cout << ans;
return 0;
}