迪杰斯特拉算法 Dijkstra

这大概是算法里名字最难记的了,不管是英文还是中文。不知道是不是受某品牌影响,笔者老是记成“迪杰特斯拉算法”。

算法简述

迪杰斯特拉算法的本质是贪心。

总体上将所有节点分成两类:已确定从起点到该节点最短路长度的节点以及未确定从起点到该节点最短路长度的节点。
每次从尚未确定距离的节点中找到距离起点最近的点作为新的确定最短路长度的节点,并用它更新从起点到其他所有尚未确定距离节点的距离,即比较路径长短(也有书把这种更新的操作叫作松弛),直到所有点都被确定长度。

常见疑惑的说明:

1.是否可能需要再次更新? 由于已经使用每一个确定最短路长度的节点更新过当前节点,故无需再次更新(因为一个点不能多次到达)。 2.为何把距离起点最近的点作为新的确定最短路长度的节点? 由于该节点是所有尚未确定距离节点中距离起点最短的点,不可能被其它尚未确定距离的节点更新。所以该节点可以作为新的确定最短路长度的节点。

代码实现

一般来说有两种方法实现:第一种是枚举法dijkstra1,第二种是用堆的方法dijkstra2实现。
class Dijkstra {
public:
    const int inf=1e9+7;
    int dijkstra1(vector<vector<int>> edges,int n,int starting)//n is the number of node
    {
        vector<vector<int>> route(n,vector<int>(n,inf));
        for(const auto &edge:edges)//record present edge
            route[edge[0]][edge[1]]=edge[2];
        
        vector<int> dst(n,inf);
        dst[starting]=0;
        vector<int> used(n);
        for(int i=0;i<n;i++)
        {
            int x=-1;
            for(int j=0;j<n;j++)
            {
                if(!used[j]&&(x==-1||dst[j]<dst[x]))//find the smallest vertex
                    x=j;
            }
            used[x]=true;//sign the vertex as passed
            for(int j=0;j<n;j++)
                dst[j]=min(dst[j],dst[x]+route[x][j]);
        }
        int ret=*max_element(dst.begin(),dst.end());
        return ret==inf?-1:ret;//perhaps there is a vertex that cannot be reached
    }
    
    int dijkstra2(vector<vector<int>> edges,int n,int starting)//n is the number of node
    {
        vector<vector<pair<int,int>>> route(n);
        for(const auto &edge:edges)//record present edge
            route[edge[0]].emplace_back(edge[1],edge[2]);
        
        vector<int> dst(n,inf);
        dst[starting]=0;
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> pq;//pq stores {distance,target}
        pq.emplace(0,starting);
        while(!pq.empty())
        {
            auto node=pq.top();
            pq.pop();
            int dis=node.first,x=node.second; 
            if(dst[x]<dis)
                continue;
            for(const auto &r:route[x])//traverse the edge starting from vertex x
            {
                int next=r.first,distance=dst[x]+r.second;//calculate the distance of next vertex from vertex x
                if(distance<dst[next])
                {
                    dst[next]=distance;
                    pq.emplace(distance,next);
                }
            }
        }

        int ret=*max_element(dst.begin(),dst.end());
        return ret==inf?-1:ret;//perhaps there is a vertex that cannot be reached
    }

};
时间复杂度 空间复杂度 补充说明 适用范围
枚举法 \(O(n^2+m)\) \(O(n^2)\) 边数大于顶点数(稠密图)
采用堆 \(O(mlogm)\) \(O(n+m)\) 顶点数大于边数(稀疏图)

m为edges长度

例题:
力扣743网络延迟时间 https://leetcode-cn.com/problems/network-delay-time/