Dijkstra堆優化


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

今天我們嘗試用堆來優化它。這里我們使用了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;
}

 


免責聲明!

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



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