Sunlight9

Dijkstra求无向图单源最短路径

Nov 27th, 2025
680
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.63 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4. // 使用 long long 防止路径总长度超过 int 范围(约 20 亿)
  5. using ll = long long;
  6.  
  7. // 定义一个极大的数表示“无穷大”。
  8. // 0x3f3f3f3f3f3f3f3f 在 long long 下是一个非常大的数,
  9. // 且两个这样的数相加一般不会溢出,非常适合做最短路的初始值。
  10. constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
  11.  
  12. // Edge 结构体有两个用途:
  13. // 1. 在邻接表 adj 中:u 表示邻接点编号,w 表示边的权重。
  14. // 2. 在优先队列 q 中:u 表示节点编号,w 表示从起点 s 到 u 的当前最短距离。
  15. struct Edge {
  16.     int u;
  17.     ll w;
  18.    
  19.     // 重载小于号运算符,用于优先队列的排序。
  20.     // C++ 的 priority_queue 默认是“大根堆”(最大值在堆顶)。
  21.     // 我们需要“小根堆”(距离最小的在堆顶),所以这里逻辑反过来:
  22.     // 如果当前 w 大于对方的 w,则认为优先级更低。
  23.     bool operator< (const Edge& o) const {
  24.         return w > o.w;
  25.     }
  26. };
  27.  
  28. int main() {
  29.     // 关闭输入输出同步流,提高 cin/cout 的读写速度,防止 TLE(超时)
  30.     ios::sync_with_stdio(false);
  31.     cin.tie(nullptr);
  32.    
  33.     int n, m, s;
  34.     cin >> n >> m >> s; // 输入点数 n,边数 m,起点 s
  35.    
  36.     // 邻接表存储图,adj[u] 存储的是从 u 出发的所有边
  37.     vector<vector<Edge> > adj(n + 1);
  38.    
  39.     // 读入 m 条边
  40.     for (int i = 1; i <= m; ++i) {
  41.         int u, v;
  42.         ll w;
  43.         cin >> u >> v >> w;
  44.         // 无向图,所以要双向建边
  45.         adj[u].push_back({v, w}); // u -> v 权重 w
  46.         adj[v].push_back({u, w}); // v -> u 权重 w
  47.     }
  48.    
  49.     // 优先队列(小根堆),存储 pair {节点 u, 距离 w}
  50.     // 堆顶永远是当前未确定的点中,距离起点最近的那个点
  51.     priority_queue<Edge> q;
  52.    
  53.     // dist 数组:存储起点 s 到各个点的最短距离,初始化为无穷大
  54.     vector<ll> dist(n + 1, inf);
  55.    
  56.     // vis 数组:标记某个点是否已经确定了最短路(是否被“出队”过)
  57.     vector<bool> vis(n + 1, false);
  58.    
  59.     // 初始状态:起点 s 到自己的距离为 0
  60.     q.push({s, 0});
  61.     dist[s] = 0;
  62.    
  63.     // Dijkstra 主循环
  64.     while (!q.empty()) {
  65.         // 取出堆顶元素(当前距离起点最近的点)
  66.         Edge now = q.top();
  67.         q.pop();
  68.        
  69.         int u = now.u; // 当前节点编号
  70.        
  71.         // 如果该点已经被访问过(即已经确定了最短路),则跳过。
  72.         // 这是因为同一个点可能多次入队(每次发现更短路径都会入队),
  73.         // 只有第一次出队时的距离才是最短的。
  74.         if (vis[u])
  75.             continue;
  76.        
  77.         // 标记该点已确定最短路
  78.         vis[u] = true;
  79.        
  80.         // 遍历 u 的所有邻接点(扫描出边)
  81.         for (int i = 0; i < adj[u].size(); ++i) {
  82.             int v = adj[u][i].u;    // 邻接点 v
  83.             ll w = adj[u][i].w;     // 边 u-v 的权重
  84.            
  85.             // 松弛操作 (Relaxation):
  86.             // 如果经由 u 到达 v 的距离(dist[u] + w)比当前记录的 dist[v] 更短
  87.             if (dist[v] > dist[u] + w) {
  88.                 dist[v] = dist[u] + w;  // 更新 v 的最短距离
  89.                 q.push({v, dist[v]});   // 将更新后的 v 放入队列,以便后续扩展
  90.             }
  91.         }
  92.     }
  93.    
  94.     // 输出从起点 s 到所有点 1~n 的最短距离
  95.     for (int i = 1; i <= n; ++i) {
  96.         cout << dist[i] << " ";
  97.     }
  98.     cout << "\n";
  99.    
  100.     return 0;
  101. }
Advertisement
Comments
  • User was banned
Add Comment
Please, Sign In to add comment