使用优先队列priority_queue来优化Dijkstra

13 篇文章 1 订阅

代码如下:

#include<bits/stdc++.h>

using namespace std;

struct node{
    int u, dis; // u 是当前点的编号, dis是u点距离起点st的距离
    node () {}
    node(int _u, int d) : u(_u), dis(d){}
    bool operator < (const node &b) const {
        return dis > b.dis;
    }
};

const int maxn = 1000;
const int INF = 1e9;
int G[maxn][maxn];
int d[maxn],n;
bool vis[maxn] = {0};

void dijkstra(int st){
    fill(d,d+maxn,INF);
    d[st] = 0;
    priority_queue<node> q;
    q.push(node(st,0)); // 起点入队
    while(q.size()){   // 只要队列不空,一直循环
        int u = q.top().u;  // 只要当前距离起点距离最小的定点的编号。注意,此处取出的定点可能已经访问了
        q.pop();   // 当前定点出队
        if(vis[u]) continue; // 如果已经访问过u,则跳过
        vis[u] = true;  // 此处,取出u时,设为已访问!!!!!!!!
        for(int v = 0;v < n;v++){   //以u为中介点,看看是否可以更新尚未访问过的点到起点的距离
            // v未被访问过、u可以到达v、从u去往v距离更小
            if(!vis[v] && G[u][v] != INF &&d[v] > d[u] + G[u][v]){
                d[v] = d[u] + G[u][v];    // 更新d[v]
                q.push(node(v,d[v]));    // 将v及d[v]入队
            }
        }
    }
}

int main() {
    fill(G[0],G[0] + maxn * maxn,INF);
    int m,st;
    scanf("%d%d%d",&n,&m,&st);
    for(int i = 0;i < m;i++){ //读入数据
        int a,b,dis;
        scanf("%d%d%d",&a,&b,&dis);
        G[a][b] = dis;
    }
    dijkstra(st);
    for(int i = 0;i < n;i++) printf("%d ",d[i]);//输出各个定点到起点的最小距离
	return 0;
}

测试样例

6 8 0   //6个点,编号0-5,8条边,起点为0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3

运行结果

0 1 5 3 4 6

提取出代码中的Dijkstra部分

void dijkstra(int st){
    fill(d,d+maxn,INF);   //初始化各个定点到起始点st的距离
    d[st] = 0;
    priority_queue<node> q;
    q.push(node(st,0));//起点入队
    while(q.size()){
        int u = q.top().u;
        q.pop();
        if(vis[u]) continue; //如果已经访问过u,则跳过
        vis[u] = true;  //此处,取出u时,设为已访问!!!!!!!!
        for(int v = 0;v < n;v++){
            //v未被访问过、u可以到达v、从u去往v距离更小
            if(!vis[v] && G[u][v] != INF &&d[v] > d[u] + G[u][v]){
                d[v] = d[u] + G[u][v];//更新d[v]
                q.push(node(v,d[v]));//将v及d[v]入队
            }
        }
    }
}

首先,优先队列的结构体中有点的编号v以及该点到起始点st的最短距离dis。并且定义了排序规则,即距离起始点最近的点在最顶部。
先定义一个优先队列,并将起始点和0组成的结构体入队,之后就是不停地循环。
注意,不是入队一个元素就将当前定点设为已访问,而是在取出队顶元素时,先判断是否已经访问过该定点,如果是的话,则continue,如果还没有访问过该顶点u,则将该顶点设为已访问,接下来以该顶点u为中介点,去看看是否可以更新一些未被访问过的顶点到起始点的距离。
也就是说,一个顶点,是可能多次入队的。
比如说,从u1到达v的距离为100,此时更新d[v] 为100,并将(v,100)入队,但是此时不可以将vis[v]设为已访问,当从u2出发,到达v的距离变为80时,更新d[v]为80,并将(v,80)入队,此时在队列中,确实是有两个v,但是一定是(v,80)比(v,100)先出队。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值