#题解/P3371 【模板】单源最短路径(弱化版)

知识点

dijkstra算法

介绍 :dijkstra算法用于求解有权图求最短路的问题

具体过程

1.将起始点的dis置为0.

2.选择当前未标记的顶点中dis值最小的一个。

3.对该顶点的所有连边依次进行松弛操作。

4.对该点进行标记。

5.重复第(2)步至第(4)步,直到不存在一条边从已标记顶点通往未标记点的连边

还有一点没说

搞清楚邻接表邻接矩阵适用于什么情况

如果不懂连边,松弛操作等名词含义欢迎拜读我的博客点我

解释:dis数组是用于记录到目前为止起点到各顶点的最短路长度

关于dis数组的细节初始化,在初始化的时候先将整个数组设置为inf,inf:表示无穷大,一般开成1e18-1或者1e9-1

题外话

其实这个算法和BFS求无权图最短路的思路差不多,基础不好的就像我一样 有点搞不懂这个dijkstra函数的形参也就是graph数组他其实存的就是比如\(u \to v\) 代价为w,那么就是graph[u].push_back({w,v}),就是存u点到v点的边权(代价),在主函数初始化的时候你可以注意到

当然我这个代码用堆优化了,也就是优先队列,也要搞懂优先队列的作用,总之你一定要知道你现在要干嘛,等下要干嘛,一定要有思路

复制代码
#include <bits/stdc++.h>
using namespace std ;

#define int long long 

vector<int>Dijkstra(int start,int n,vector<vector<pair<int,int> > >& graph)
{
    const int INF = INT_MAX ;
    vector<int>dis(n+1,INF) ;
    dis[start] = 0 ;
  //存{距离,节点} 
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int> > >q;
    q.push({0,start});
    while(!q.empty())
    {
        int d = q.top().first ;
        int u = q.top().second ;
        q.pop() ;
        if(d > dis[u]) continue ;/*
在堆优化的 Dijkstra 中,我们无法直接更新队列内部某个节点的值。所以,当发现一条更短的路径时,我们并不是"修改"队列里的旧距离,而是直接塞进去一个新的、更短的距离。
这就导致:同一个节点在队列里可能同时存在多份数据。*/
//简单来说,它的核心作用是:跳过那些已经被发现"不是最短"的路径信息
        for(auto & edge : graph[u])
        {
            int v = edge.first ; //目标节点
            int w = edge.second ; //边权
            if(dis[u] + w < dis[v])
            {
                dis[v] = dis[u] + w ;
                q.push({dis[v],v}) ;
            }
        }
    }
    return dis ;
}

signed main()
{
    ios::sync_with_stdio(false),cin.tie(nullptr) ;
    
    int n,m,s;
    cin >> n >> m >> s;
    // 邻接表:graph[u]存储从u出发的所有边 {v, w}
    vector<vector<pair<int, int>>> graph(n + 1);  // 1-indexed
    for(int i = 0;i < m;i++)
    {
        int u,v,w;
        cin >> u >> v >> w ;
        graph[u].push_back({v, w});
    }
    vector<int> dist = Dijkstra(s, n, graph);
    
     for (int i = 1; i <= n; i++) {
        if (dist[i] == INT_MAX) {
            cout << 2147483647 << " ";  // 不能到达
        } else {
            cout << dist[i] << " ";
        }
    }
    cout << endl;

    return 0 ;
}