leetcode:743. 网络延迟时间

题目来源

题目描述

在这里插入图片描述

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {

    }
};

题目解析

  • 题目实际上是求节点K到其他所有点中最远的距离,那么首先需要求出节点K到其他所有点的最短路,然后取最大值即可。

Dijkstra 算法

  • 单源最短路问题可以使用 Dijkstra 算法,其核心思路是贪心算法。流程如下:
    • 首先,Dijkstra 算法需要从当前全部未确定最短路的点中,找到距离源点最短的点 x。
    • 其次,通过点x更新其他所有点距离源点的最短距离。比如目前点A距离源点最短,距离为3;有一条边A->B的有向边,权值为1,那么源点先去A点再去B点距离为3+1=4
    • 当全部其他点都遍历完成后,一次循环结束,将x标记为已经确定的最短路。进入下一轮循环,直到全部点被标记为确定了最短路。
  • Dijkstra算法可以视为使用贪心策略优化后的广度优先搜索

我们通过一个[例子]对 Dijkstra 算法的流程深入了解一下:

在这里插入图片描述

以上图片为一个有向带权图,圆圈中为节点序号,箭头上为边权,右侧为所有点距离源点 0 的距离。

在这里插入图片描述
将顶点 0 进行标识,并作为点 xx,更新其到其他所有点的距离。一轮循环结束。
在这里插入图片描述
在这里插入图片描述
将顶点 2 进行标识,并作为新的点 x,更新。我们看到,原本点 1 的最短距离为 5,被更新为了 3。同理还更新了点 3 和点 4 的最短距离。
在这里插入图片描述
在这里插入图片描述
将顶点 1 进行标识,并作为新的点 xx,同样更新了点 4 到源点的最短距离。

在这里插入图片描述
再分别标识点 4 和点 3,循环结束。

我们来看实现时需要的代码支持:
在这里插入图片描述

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        const int inf = INT32_MAX / 2;

        // 邻接矩阵存储边信息
        std::vector<std::vector<int>> g(n, std::vector<int>(n, inf));
        for(auto & t : times){
            // 边序号从 0 开始
            int x = t[0] - 1, y = t[1] -1;
            g[x][y] = t[2];
        }

        // 从源点到某点的距离数组
        std::vector<int> dist(n, inf);
        dist[k - 1] = 0;  // 由于从 k 开始,所以该点距离设为 0,也即源点

        // 节点是否被更新数组
        std::vector<bool> used(n);
        for (int i = 0; i < n; ++i) {
            // 在还未确定最短路的点中,寻找距离最小的点
            int x = -1;
            for (int y = 0; y < n; ++y) {
                if(!used[y] && (x == -1 || dist[y] < dist[x])){
                    x = y;
                }
            }

            // 用该点更新所有其他点的距离
            used[x] = true;
            for (int y = 0; y < n; ++y) {
                dist[y] = std::min(dist[y], dist[x] + g[x][y]);
            }
        }

        // 找到距离最远的点
        int ans = *max_element(dist.begin(), dist.end());
        return ans == inf ? -1 : ans;
    }
};

用优先队列(堆实现)优化迪杰斯特拉算法

#define MAXVALUE 0x3f3f3f3f

class Solution {
public:
    vector<unordered_map<int, int>> mp;
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        // 建图 - 邻接表
        mp.resize(n + 1);
        for (auto& edg : times) {
            mp[edg[0]][edg[1]] = edg[2];
        }
        // 记录结点最早收到信号的时间
        vector<int> r(n + 1, MAXVALUE);

        // 优先队列中存放 [收到信号时间,结点]
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> s;
        s.emplace(pair(0, k));

        while (!s.empty()) {
            auto cur = s.top();
            s.pop();
            if (r[cur.second] != MAXVALUE) continue;
            r[cur.second] = cur.first;

            for (auto& edg : mp[cur.second]) {
                if (r[edg.first] == MAXVALUE) {
                    s.emplace(pair(edg.second + cur.first, edg.first));
                }
            }
        }

        int minT = -1;
        for (int i = 1; i <= n; ++i)
            minT = max(minT, r[i]);
        return minT == MAXVALUE ? -1 : minT;
    }
};

深度优先搜索

简单递归的搜索一遍图,当然继续向下搜索的前提是遍历到某一结点的时间有所改善,不然没必要继续向下继续搜索了,不过其实 DFS 对于求最短路并不合适

#define MAXVALUE 0x3f3f3f3f

class Solution {
public:
    vector<unordered_map<int, int>> mp;
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        // 建图 - 邻接表
        mp.resize(n + 1);
        for (auto& edg : times) {
            mp[edg[0]][edg[1]] = edg[2];
        }
        // 记录结点最早收到信号的时间
        vector<int> r(n + 1, MAXVALUE);

        dfs(r, k, 0);

        int minT = -1;
        for (int i = 1; i <= n; ++i)
            minT = max(minT, r[i]);
        return minT == MAXVALUE ? -1 : minT;
    }

    void dfs(vector<int>& r, int i, int t) {
        if (r[i] > t) {
            r[i] = t;
            for (auto& cur : mp[i]) {
                dfs(r, cur.first, cur.second + t);
            }
        }
    }
};

广度优先搜索

涉及最大最小的问题 BFS 显然比 DFS 更合适

class Solution {
    const int inf = INT32_MAX / 2;
    std::vector<std::unordered_map<int, int>> mp;
    
    struct Info{
        int node;
        int time;
        
        Info(int n, int t) : node(n), time(t){
            
        }
    };
public:
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        // 建图 - 邻接表
        mp.resize(n + 1);
        for(auto &edg : times){
            mp[edg[0]][edg[1]] = edg[2];
        }
        // 记录结点最早收到信号的时间
        std::vector<int> dist(n + 1, inf);
        dist[k] = 0;
        // 队列中存放 [结点,收到信号时间]
        queue<Info> s;
        s.emplace(Info{k, 0});
        
        while (!s.empty()){
            auto cur = s.front();
            s.pop();
            for(auto &edg : mp[cur.node]){
                int time = edg.second + cur.time;
                // 仅当结点收到时间比记录时间更早才更新并入队
                if(time < dist[edg.first]){
                    dist[edg.first] = time;
                    s.emplace(Info(edg.first, time));
                }
            }
        }
        
        
        // 找到距离最远的点
        int ans = *max_element(dist.begin(), dist.end());
        return ans == inf ? -1 : ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值