Questions related to dijkstra algorithm (using adjacency list and priority queue methods)

I won’t go into detail about the Dijkstra algorithm because there are too many posts to explain it, and this is just my personal summary/record. I will write my thinking process in the comments of the code.

743. Network delay time (directed graph)

There are n network nodes, labeled 1 to n.

Give you a list times, which represents the time when the signal passes through the directed edge. times[i] = (ui, vi, wi), where ui is the source node, vi is the target node, and wi is the time for a signal to be transmitted from the source node to the target node.

Now, a signal is sent from some node K. How long does it take for all nodes to receive the signal? If all nodes cannot receive the signal, -1 is returned.

Insert image description here

1. Adjacency list method

	class Solution {
    
    
public:
    // distances数组 保存:起点k 到其他点的最短距离
    // visited数组 保存:某点是否被访问过了,被访问过则设置为true
    // graph 二维数组:邻接表
    // n : 节点总数
    void dijkstra(vector<vector<long long>>& graph,vector<int>& distances,int n,int k,vector<bool>& visited){
    
    
        distances[k] = 0;// 起始点到起始点自身的距离为0

        // 这里只需要循环 n-1次
        // 原因:除k点以外只有 n-1个点,每循环一次,就更新k点到一个点的距离
        for(int i = 1;i<=n-1;i++){
    
    
            int id = 0,minDistance = INT_MAX;
            for(int j = 1;j<=n;j++){
    
    
                // 这个循环的目的:去找 距离 k点最近的点
                // 原因:可以通过 这个点,去更新 其他点到 k点的距离
                if(!visited[j] && distances[j]<minDistance){
    
    
                    minDistance = distances[j];
                    id = j;
                }
            }
            // 所有点都被访问过了 或者 所有点都不可达
            if(id == 0) return;
            visited[id] = true;

            // 得到一个中间点 id后,比较k->id->某一点的距离 和 k->某一点的距离 
            // 来更新distances数组,注意,这个数组存的是k到某一点的距离
            for(int j = 1;j<=n;j++){
    
    
                if(!visited[j] && distances[id]+graph[id][j]<distances[j]){
    
    
                    distances[j] = distances[id]+graph[id][j];
                }
            }
        }
    }

    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
    
    
        vector<vector<long long>> graph(n+1,vector<long long>(n+1,INT_MAX));
        vector<int> distances(n+1,INT_MAX);
        vector<bool> visited(n+1,false);

        // 建立邻接表
        for(auto t:times){
    
    
            int u = t[0],v = t[1],w = t[2];
            graph[u][v] = w;
        }

        //dijkstra算法
        dijkstra(graph,distances,n,k,visited);

        int ans = 0;
        for(int i = 1;i<=n;i++){
    
    
            if(distances[i] == INT_MAX) return -1;
            ans = max(ans,distances[i]);
        }
        return ans;
    }
};

2. Priority queue

class Solution {
    
    
public:
    void dijktra(vector<vector<int>>& times,vector<int>& dis, int n, int k){
    
    
        dis[k] = 0;
        using Pair = pair<int,int>; // first是距离,second是目标点
        priority_queue<Pair,vector<Pair>, greater<Pair>> pq;

        pq.push({
    
    0,k});

        while(!pq.empty()){
    
    
            auto e = pq.top();
            pq.pop();
            if(e.first>dis[e.second]) continue;
            for(int i = 0;i<times.size();i++){
    
    
                if(times[i][0] == e.second){
    
    
                    int v = times[i][1];
                    // 到v点的的距离
                    int w = e.first+times[i][2];
                    if(dis[v]==-1 || dis[v]>w){
    
    
                        dis[v] = w;
                        pq.emplace(w,v);
                    }
                }
            }
        }
    }

    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
    
    
        vector<int> dis(n+1,-1);

        dijktra(times,dis,n,k);

        int ans = 0;
        for(int i = 1;i<=n;i++){
    
    
            if(dis[i]==-1) return -1;
            ans = max(ans,dis[i]);
        }
        return ans;
    }
};

1334. The city with the fewest neighbors within the threshold distance

There are n cities, numbered from 0 to n-1. Give you an edge array edges, where edges[i] = [fromi, toi, weighti] represents the two-way weighted edge between the two cities fromi and toi, and the distance threshold is an integer distanceThreshold.

Returns the city with the smallest number of other cities that can be reached through certain paths and the largest path distance of distanceThreshold. If there are multiple such cities, the city with the highest number is returned.

Note that the distance of the path connecting cities i and j is equal to the sum of the weights of all edges along the path.

Insert image description here

1. Adjacency list method

class Solution {
    
    
public:
    void Dijkstra(vector<vector<long long>>& graph,vector<int>& distances,vector<bool> &visited,int n,int distanceThreshold,int start){
    
    
        // 自身到自身的距离为0
        distances[start] = 0;

        for(int i = 0;i<n-1;i++){
    
    
            int u = -1,minDis = INT_MAX;
            // 下面这个这个循环的目的:
            // 为了在 和 start 点相连的所有点中找到一个最近的点,再把它设为新的起点
            for(int j = 0;j<n;j++){
    
    
                if(!visited[j] && distances[j] <minDis){
    
    
                    u = j; // 设置新的起点
                    minDis =distances[j];
                }
            }
            // 如果所有点都访问过了 或者 不可达,直接return 即可
            if(u==-1) return;
            // 把新的起点设置为访问过
            visited[u] = true;

            // 接下来更新 start到所有点的 新的 距离
            // 为什么有新的距离?
            // 回答:因为此时我们有了一个新的点,那么从 start点开始到其他点就不止一种直连路线
            // 而是可以借助 刚刚确立好的新的点 ,比如从 start到某点 需要距离为5
            // 而start 到 u 的距离为1,u到某点的距离为2,那么就可以更新新的距离了
            for(int j = 0;j<n;j++){
    
    
                // 注意:仍然需要不去管那些已经访问过的节点
                //因为已经访问过的节点就已经是最短的距离了
                if(!visited[j] && distances[u]+graph[u][j]<distances[j]){
    
    
                    distances[j] = distances[u]+graph[u][j];
                }
            }
        }
    }

    //  使用Dijkstra算法,邻接矩阵版
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
    
    
        vector<vector<long long>> graph(n,vector<long long>(n,INT_MAX));// 邻接矩阵
        for(auto edge:edges){
    
    
            int u = edge[0],v = edge[1],w = edge[2];
            graph[u][v] = graph[v][u] = w;
        }

        // minCount:在指定的阈值内可以 到达节点 的最少数量
        int idx = -1,minCount = INT_MAX;
        for(int i = 0;i<n;i++){
    
    
            vector<int> distances(n,INT_MAX);// 单源最短路径数组
            vector<bool> visited(n,false); // 用来记录某一节点是否被访问过
            // 调用函数可以得到从i点出发到其他各个点的最短距离
            // 这些距离被保存在distances数组中
            Dijkstra(graph,distances,visited,n,distanceThreshold,i);
            int count = 0; // 小于等于阈值的城市个数
            for(int j = 0;j<n;j++){
    
    
                if(i!=j && distances[j] <= distanceThreshold  ){
    
    
                    count++;
                }
            }
            if(count<=minCount){
    
    
                minCount = count;
                // 保存当下这个出发点
                idx = i;
            }
        }
        return idx;
    }
};

2. Priority queue

class Solution {
    
     //优先队列版
public:
    void Dijkstra(vector<vector<int>>& graph, vector<int>& distances, int n, int distanceThreshold, int start) {
    
    
        //小顶堆,按照距离dist从小到大排序,pair中first存dist
        priority_queue <pair<int, int>,vector<pair<int, int>>, greater<pair<int, int>>> q;
        distances[start] = 0;
        q.push({
    
    distances[start],start});
        while (!q.empty()) {
    
    
            pair<int, int>p = q.top();
            int u = p.second;
            q.pop();
            if (distances[u] < p.first) {
    
    
                continue;
            }
            for (int v=0; v<n; ++v) {
    
    
                if (graph[u][v] != INT_MAX && distances[v]>distances[u]+graph[u][v]) {
    
    
                    distances[v]=distances[u]+graph[u][v];
                        q.push({
    
    distances[v],v});
                }
            }
        }
    }
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
    
    
        vector<vector<int>>graph(n,vector<int>(n,INT_MAX)); //邻接矩阵
        for (vector<int> edge : edges) {
    
    
            int u=edge[0], v=edge[1], w=edge[2];
            graph[u][v] = graph[v][u] = w;
        }
        int idx = -1, minCount = INT_MAX;
        for (int i=0; i<n; ++i) {
    
    
            vector<int>distances(n,INT_MAX); //单源最短路径数组
            Dijkstra(graph, distances, n, distanceThreshold, i);
            int count = 0; //小于等于距离阈值的城市个数
            for (int j=0; j<n; ++j) {
    
    
                if (distances[j]<=distanceThreshold && i!=j) {
    
    
                    count++;
                }
            }
            if (count <= minCount) {
    
    
                minCount = count;
                idx = i;
            }
        }
        return idx;
    }
};

1514. The path with the highest probability

Give you an undirected weighted graph consisting of n nodes (the subscripts start from 0). The graph consists of a list describing edges, where edges[i] = [a, b] represents a link connecting nodes a and b. There is an undirected edge, and the probability of successful traversal of this edge is succProb[i].

Specify two nodes as the starting point start and the end point end respectively. Please find the path with the highest success probability from the starting point to the end point and return its success probability.

If there is no path from start to end, return 0. As long as the error between the answer and the standard answer does not exceed 1e-5, it will be regarded as the correct answer.

Insert image description here

Using the bow tie table in this question will exceed the memory limit, so this question requires some minor changes, and does not require a visited array. In my opinion, the solution to this question is the optimal way to write Dijkstra's algorithm.

class Solution {
    
    
public:
    struct cmp{
    
    
        bool operator()(pair<double,int> a,pair<double,int> b)const{
    
    
            return a.first<b.first;// 升序排列
        }
    };
    
    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {
    
    
        vector<vector<pair<double,int>>> graph(n);
        for(int i = 0;i<edges.size();i++){
    
    
            auto &e = edges[i];
            graph[e[0]].emplace_back(succProb[i],e[1]);
            graph[e[1]].emplace_back(succProb[i],e[0]);
        }

        priority_queue<pair<double,int>,vector<pair<double,int>>,cmp> que;

        vector<double> prob(n,0);

        que.emplace(1,start_node);
        prob[start_node] = 1;

        while(!que.empty()){
    
    
            auto [pr,node] = que.top();
            que.pop();
            if(pr<prob[node]) continue;

            for(auto &[prNext,nodeNext]:graph[node]){
    
    
                if(prob[nodeNext]<prNext * prob[node]){
    
    
                    prob[nodeNext] = prNext * prob[node];
                    que.emplace(prob[nodeNext],nodeNext);
                }
            }
        }
        return prob[end_node];
    }
};

at last:

In fact, the dijkstra algorithm (adjacency list version) is used the same for directed graphs and undirected graphs, and there is no difference. I used to wonder if the situation would be different if I swapped 0 and 3 in [0,3,2], but the answer is no. Because when building the adjacency list, the two-way distance is set. If the order is changed, but starting from another point, the distance is still the same, and there is no need to worry about repeated visits, because the visited array is used to distinguish .

Guess you like

Origin blog.csdn.net/weixin_47505105/article/details/132109250
Recommended