最短路之 $dijkstra$ 学习笔记

最短路之 \(dijkstra\) 学习笔记

复习 \(dijkstra!\)

怎么说,就写一下 \(dij\) 的实现过程吧

\(dij\) 的思路就是,

将结点分成两个集合:已确定最短路长度的点集(记为$ S$集合)的和未确定最短路长度的点集(记为 $ T$ 集合)。一开始所有的点都属于 $ T $ 集合。

初始化 $dis(s)= 0 $ ,其他点的 $dis $ 均为 $+ \infty $。

然后重复这些操作:

  1. 从$ T $ 集合中,选取一个最短路长度最小的结点,移到 $ S $ 集合中。
  2. 对那些刚刚被加入 $S $ 集合的结点的所有出边指向的点更新距离并放入队列。

直到 $T $ 集合为空,算法结束。

把图上的点分成两个集合,一个是已经确定最短路的集合 \(S\) 和剩下的点 \(S'\)

同时用一个优先队列 \(Q\) 来维护与 \(S\) 中的点相邻的点中到起点 \(s\) 的目前的最短距离(这个地方用 \(pair\) 来同时存距离和点的编号)

然后实现步骤就是

每次取出 \(Q\) 的队头也就是目前不在 \(S\) 之中到起点 \(s\) 距离最近的点 \(i\)

如果这个点之前没被取出来过,也就是没被标记过,不在 \(S\) 之中

则将其标记,也就是放到 \(S\) 中 然后依次遍历 \(i\) 点的所有相邻的节点 \(t\)

如果 \(t\) 不在 \(S\) 之中 且 \(dis(s,i)+dis(i,t)<dis(s,t)\) 的话,就将 \(t\) 放到 \(Q\)

\(Q\) 重新变为空时,最短路就求好了

时间复杂度

\(O(m\log n+nk\log n) \approx O(m\log n)\)

其中k为每个点的平均邻居数

代码如下

#include <bits/stdc++.h>
using namespace std;
int n, m, k;

struct edge
{
    int f, t;
    int w;
};
edge edges[1000000];
struct node
{
    bool done;
    int dis = 1099999999;
    vector<int> to;
    int num;
    void clear()
    {
        this->done = 0;
        this->dis = 2147483647;
    }
};

node nodes[300000];
//第一关键字是距离,第二关键字是节点编号
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;

void dij(int start_)
{
    int the_bian, the_dis, temp_dis, to_;
    q.push({0, start_});
    nodes[start_].dis = 0;
    while (!q.empty())
    {
        pair<int, int> the_node = q.top();
        q.pop();
        the_dis = the_node.first;
        the_bian = the_node.second;
        if (!nodes[the_bian].done)
        {
            nodes[the_bian].done = 1;//标记,放入S中
            for (int yy = 0; yy < nodes[the_bian].to.size(); yy++)//便利这个点的所有出边
            {
                to_ = edges[nodes[the_bian].to[yy]].t;

                temp_dis = nodes[the_bian].dis + edges[nodes[the_bian].to[yy]].w;
                if (temp_dis < nodes[to_].dis)
                {
                    nodes[to_].dis=temp_dis;//更改距离
                    q.push({temp_dis, to_});//入队
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    int aa, bb, cc;
    for (int ww = 1; ww <= m; ww++)
    {
        cin >> aa >> bb >> cc;//建边
        edges[ww].f = aa;
        edges[ww].t = bb;
        edges[ww].w = cc;
        // edges[ww + m].f = bb;
        // edges[ww + m].t = aa;
        // edges[ww + m].w = cc;
        nodes[aa].to.push_back(ww);
       // nodes[bb].to.push_back(ww + m);
    }
    dij(k);
    for (int yy = 1; yy <= n; yy++)
    {
        cout << nodes[yy].dis << " ";
    }

    return 0;
}
posted @ 2024-09-14 17:46  sea-and-sky  阅读(7)  评论(1编辑  收藏  举报