dijkstra算法的堆优化

普通的dijkstra算法模板:

//数据结构
int g[LEN][LEN];    //邻接矩阵 
int vis[LEN];        //标记是否访问
int dist[LEN]         //源点到各点的距离

fill(dist,dist+LEN,MAX);
dist[s]=0;
while(1){
    int u=-1,d=MAX;
    for(int i=0;i<N;i++){
        if(!vis[i] && dist[i]<d){
            d=dist[i];
            u=i;
        }
    }
    if(u<0) break;
    vis[u]=1;
    for(int i=0;i<N;i++) if(!vis[i]){
        if(dist[u]+g[u][i]<dist[i]){
            dist[i]=dist[u]+g[u][i];
        }
    }
} 

为了能在“取出最小的dist”这一步实现优化,我们使用priority_queue进行优化。下面用cmp结构体重载括号运算符priority_queue进行改造:

struct cmp{
    bool operator () (int a,int b){
        return dist[a]>dist[b];
    }
};
priority_queue<int,vector<int>,cmp> pq;

然后我们来看堆优化的dijkstra算法:

//数据结构
int g[LEN][LEN];    //邻接矩阵 
int vis[LEN];        //标记是否访问
int dist[LEN]         //源点到各点的距离
struct cmp{
    bool operator () (int a,int b){
        return dist[a]>dist[b];
    }
};
priority_queue<int,vector<int>,cmp> pq;

fill(dist,dist+LEN,MAX);
dist[s]=0;
pq.push(s);
while(!pq.empty()){
    int u=pq.top();
    pq.pop();
    if(vis[u]) continue;
    vis[u]=1;
    for(int i=0;i<N;i++) if(!vis[i]){
        if(dist[u]+g[u][i]<dist[i]){
            dist[i]=dist[u]+g[u][i];
            pq.push(i);
        }
    }
} 

加粗的代码是未优化dijkstra所没有的。

每次更新结点,都把新的结点存到优先队列中去。

用一道例题练手。OJ链接:Travel Plan

AC代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>

#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 1010
#define MAX (1<<30)-1
#define V vector<int>

using namespace std;

int g_dist[LEN][LEN];
int g_cost[LEN][LEN];
int vis[LEN];
int dist[LEN];
int cost[LEN];
int pre[LEN];

struct cmp{
    bool operator () (int a,int b){
        return dist[a]>dist[b];
    }
};
priority_queue<int,vector<int>,cmp> pq;

int main(){
//    freopen("1030.txt","r",stdin);
    int n,m,s,e,i,j,a,b,c,d,t;
    I("%d%d%d%d",&n,&m,&s,&e);
    fill(g_dist[0],g_dist[0]+LEN*LEN,MAX);
    FF(i,m){
        I("%d%d%d%d",&a,&b,&c,&d);
        g_dist[a][b]=c;
        g_dist[b][a]=c;
        g_cost[a][b]=d;
        g_cost[b][a]=d;
    }
    fill(dist,dist+LEN,MAX);
    fill(cost,cost+LEN,MAX);
    cost[s]=0;
    pre[s]=-1;
    //加入堆优化 
    pq.push(s);    //源点入队 
    dist[s]=0;
    while(!pq.empty()){
        int u=pq.top();
        pq.pop();
        if(vis[u]) continue;
        vis[u]=1;
        FF(i,n) if(!vis[i]){
            if(dist[u]+g_dist[u][i]<dist[i] || (dist[u]+g_dist[u][i]==dist[i] && cost[u]+g_cost[u][i]<cost[i])){
                dist[i]=dist[u]+g_dist[u][i];
                cost[i]=cost[u]+g_cost[u][i];
                pre[i]=u;
                //如果通过u点更新了一个i点,那么i点入队。
                pq.push(i);
            }
        }
    }
    vector<int> path;
    i=e;
    while(i!=-1){
        path.insert(path.begin(),i);
        i=pre[i];
    }
    FF(i,path.size()) O("%d ",path[i]);
    printf("%d %d
",dist[e],cost[e]) ;
    return 0;
}
原文地址:https://www.cnblogs.com/TQCAI/p/8545162.html