Dijkstra+优先队列 堆优化

关于堆优化

传统\(Dijkstra\),在选取中转站时,是遍历取当前最小距离节点,但是我们其实可以利用小根堆(STL的priority_queue)优化这个过程,从而大大降低复杂(\(O(V^2+E) -> O((V+E)lgV)\)

另外,需要注意,因为\(Dijkstra\)本质是贪心,每一次选择中转站必须保证最优,而负边权会使当前中转站不为最优,所以不能处理含有负边权的图

代码

#include <cstdio>
#include <queue>
#include <vector>
#define MAXN 200010
#define INF 0x3fffffff
using namespace std;
struct edge{
    int v,w;
    edge(int v, int w):v(v),w(w){}
};
vector <edge> mp[MAXN];
int dis[MAXN];
bool vis[MAXN];
int n,m,s;
struct node{
    int v,dis;
    node(int v, int dis):v(v),dis(dis){}
    const bool operator < (const node &a) const{
        return a.dis < dis;
    }
};
priority_queue <node> q;

int read(){
    char ch;int s=0;
    ch = getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s;
}

void dj(){
    for(register int i=1;i<=n;i++)
        dis[i]=INF;
    dis[s]=0;
    q.push(node(s, 0));
    while(!q.empty()){
        node cur = q.top();
        q.pop();
        if(vis[cur.v])  continue;
        vis[cur.v] = 1;
        for(register int i=0;i<mp[cur.v].size();i++){
            edge to = mp[cur.v][i];
            if(vis[to.v]) continue;
            if(dis[to.v]>to.w+dis[cur.v]){
                dis[to.v]=to.w+dis[cur.v], q.push(node(to.v, dis[to.v]));
            }
        }
    }
    for(register int i=1;i<=n;i++)
        printf("%d ", dis[i]);
}

int main()
{
    n=read(),m=read(),s=read();
    for(register int i=1;i<=m;i++){
        int u,v,w;
        u=read(),v=read(),w=read();
        mp[u].push_back(edge(v, w));
    }
    dj();
    return 0;
}

参考

水郁 - Dijkstra+heap和SPFA的区别

posted @ 2019-03-01 18:12  Santiego  阅读(2175)  评论(0编辑  收藏  举报