迪杰斯特拉算法优先队列优化

前置内容

迪杰斯特拉算法基础请看:迪杰斯特拉算法

算法优化方法

当数据量较大时, 直接使用迪杰斯特拉会超时, 这个时候可以使用优先队列对算法进行优化

迪杰斯特拉算法的每一轮, 都需要找一个未被访问且距离起点最近的点来进行操作, 这个寻找的过程需要遍历距离数组, 比较耗时; 当我们每次更新一个点的距离时, 可以将当前点与距离组合成pair, 放入优先队列, 优先队列以距离排序, 使得队首为距离最小元素, 这样, 每次取出队首, 就可以知道距离起始点最近的点, 大大优化计算时间。

题目链接

洛谷P2984 [USACO10FEB] Chocolate Giving S

程序示例

#include<bits/stdc++.h>
using namespace std;

// 定义一个较大的数表示无穷大,用于初始化距离数组
#define INF 0x3f3f3f3f

// 定义比较结构体,用于优先队列中元素的比较
// 重载 () 运算符,使得优先队列按照距离(pair 的第二个元素)从小到大排序
struct cmp
{
    bool operator()(const pair<int, int> a, const pair<int, int> b)
    {
        return a.second > b.second;
    }
};

// 定义结构体表示图中的边,包含目标节点 v 和边的长度 L
struct Node
{
    int v;
    int L;
};

// 定义常量 N 表示最大的节点数
const int N = 50005;

// 定义布尔数组 vis,用于标记节点是否已访问过
bool vis[N];

// 定义数组 dis,用于存储从起点到各个节点的最短距离
int dis[N];

int main()
{
    // 读取农场数量 n,边的数量 m,询问的数量 b
    int n, m, b; 
    cin >> n >> m >> b;
    
    // 定义邻接表 g,用于存储图的结构,每个节点对应一个边的列表
    vector<Node> g[n + 1];
    
    // 定义优先队列 pq,用于实现迪杰斯特拉算法中的节点选择,按照距离从小到大排序
    priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> pq;
    
    int u, v, l; 
    // 读取每条边的信息,包括两个端点 u, v 和边的长度 l,并将边加入邻接表
    while(m--)
    {
        cin >> u >> v >> l;
        g[u].push_back({v, l});
        g[v].push_back({u, l});
    }
    // 迪杰斯特拉算法
    
    // 将距离数组 dis 初始化为无穷大,表示初始时不知道到各个节点的最短距离
    fill(dis, dis + n + 1, INF);
    
    // 将起点(编号为 1 的农场)到自身的距离初始化为 0
    dis[1] = 0;
    
    // 将起点和其距离(0)加入优先队列,准备开始算法
    pq.push({1, 0});
    
    // 当优先队列不为空时,继续执行迪杰斯特拉算法
    while(!pq.empty())
    {
        // 取出优先队列队首, 即距离起点最近的节点
        int h = pq.top().first; 
        pq.pop();
        
        // 如果该节点已经访问过,则跳过
        if(vis[h]) continue;
        
        // 标记该节点为已访问
        vis[h] = 1;
        
        // 遍历该节点的所有邻接边
        for(auto t : g[h])
        {
            int v = t.v; 
            int L = t.L;
            // 如果邻接节点未访问过,并且通过当前节点到邻接节点的距离更短
            if(!vis[v] && dis[v] > dis[h] + L)
            {
                // 更新邻接节点的最短距离
                dis[v] = dis[h] + L;
                // 将更新后的邻接节点及其距离加入优先队列
                pq.push({v, dis[v]});
            }
        }
    }    
    
    // 处理 B 次询问,每次询问输出从起点到两个节点的最短距离之和
    while(b--)
    {
        cin >> u >> v;
        cout << dis[u] + dis[v] << endl;
    }    
    
    return 0;
}

优先队列:priority_queue的内容, 请自行查询相关资料, 无需太过详细, 只需知道如何定义优先队列, 如何设定优先队列排序规则即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值