Dijkstra堆優化

Dijkstra是一個很是不錯的最短路算法,它使用兩層循環進行枚舉,經過每次更新藍白點的方式更新最短路,時間複雜度爲O(n^2),優於floyd的O(n^3),不過只能用於計算單源最短路,並且沒法處理負權邊。ios

今天咱們嘗試用堆來優化它。這裏咱們使用了STL中的set和pair。set自己至關於一個小根堆,內部自動從小到大排序。(聽說內部使用平衡樹實現?蒟蒻瑟瑟發抖。)操做方式大體就是insert(插入)和erase(刪除),不過他會把相同的數據融合到一塊兒,若是不想這樣可使用multiset。對於堆的遍歷咱們不能像數組同樣直接遍歷,而是要使用迭代器。(用法下面代碼有)而pair至關於一個有兩個成員的且已經重定義的struct,使用makepair來新構造一個pair。算法

具體怎麼作呢?咱們從起點出發,而後枚舉每一條能走到的邊(這裏使用了鄰接表存圖),以後在選取最短的一條邊時,咱們使用堆便可,也就是將貪心變成了堆,這樣時間複雜度就變爲了O(nlogn)。數組

直接上代碼看一下就好啦!優化

#include<cstdio> #include<vector> #include<cmath> #include<iostream> #include<algorithm> #include<cstring> #include<cstdlib> #include<set> #include<map> #include<queue>
#define mp make_pair
#define fi first
#define sc second
#define faker(i,a,n) for(int i = a;i <= n;i++)
#define duke(i,n,a) for(int i = n;i >= a;i--)
const int M = 100001; int v[M],num,next[M],head[M],cost[M],dis[M]; bool vis[M]; int n,m,x,y,z; using namespace std; typedef pair<int,int> pr;//pair等於有兩個成員且已經重定義的struct
void add(int x,int y,int z)//鄰接表存圖
{ v[++num] = y; next[num] = head[x]; cost[num] = z; head[x] = num; } int read() { int num = 0; char ch,last = ' '; ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') last = ch; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } if(last == '-') ans = -ans; return ans; } set<pr> q;//定義一個堆
set<pr> :: iterator it;//迭代器定義
int main() { n = read(),m = read(); faker(i,1,m)//循環(不要問我爲何有這麼奇怪的名字)
 { x = read(),y = read(),z = read(); add(x,y,z); } faker(i,1,n) dis[i] = 1000000000; dis[1] = 0; q.insert(mp(dis[1],1));//將起點壓入堆
    faker(i,1,n) vis[i] = 0; while(!q.empty()) { pr u = *(q.begin()); q.erase(q.begin());//刪除堆頂元素
        vis[u.sc] = 1;//設置爲走過
        for(int i = head[u.sc];i;i = next[i]) { if(dis[v[i]] > dis[u.sc] + cost[i]) { it = q.find(mp(dis[v[i]],v[i])); if(it != q.end())q.erase(it);//將當前較長的路徑刪除
                dis[v[i]] = dis[u.sc] + cost[i];//更新距離
                q.insert(mp(dis[v[i]],v[i]));//更新 ,壓入更短的路徑
 } } } return 0; }
相關文章
相關標籤/搜索