[LeetCode] LeetCode中与有向图相关的题目总结

相关题

LeetCode中有向图相关的题的题号为:743,685,684,399,332,310,210

743. 网络延迟时间

有 N 个网络节点,标记为 1 到 N。

给定一个列表 times,表示信号经过有向边的传递时间。 times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个信号从源节点传递到目标节点的时间。

现在,我们从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1。
在这里插入图片描述
解题思路:本题本质上在考察最短路径算法,最短路径算法有单源最短路,多源最短路,然后还掺杂着有权,无权,有向,无向。单源最短路有Dijkstra算法,贝尔福特慢算法(Bellman-Ford Algorithm),Dijkstra算法是模仿图的广度优先遍历(BFS)写的,类似水滴荡起的纹波、迷宫找路等场景。Dijkstra算法首先维护一个dist数组参与松弛操作(Relaxation),当dist[u]>dist[v]+e[u,v],更新路径值dist[u]=dist[v]+e[u,v],防止重复搜索,用visited数组标记已访问过的节点。此题解法我和Grandyang的解法大致相同,但是我的visited数组作为全局变量时,有一半的test case无法通过,不太理解为什么visited作为局部变量就能AC,我在 考虑这个问题的时候思考的方向是,想象水滴荡起纹波的场景,visited作为局部变量,最直接的表象是防止同一层的节点再次被访问,但是将visited作为全局变量,也能达到这个效果,而且也没有干扰dist[u]的更新(之前干过,将visited数组先于dist[u]关系的判断,导致有些节点当放置靠后的位置访问时,能使dist[u]更小),想到这,思路就短路了,接不上了,日后看到此题再思考╮(╯▽╰)╭

在不完全理解此题解法时,也当记住最短路在应用Dijkstra算法时,将visited数组放在层内判断的一种写法。

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        unordered_map<int, vector<pair<int, int>>> g;
        for (auto t : times) {
            g[t[0]].push_back({t[1], t[2]});
        }
        vector<int> dist(N + 1, INT_MAX);
        
        queue<int> q{{K}};
        dist[K] = 0;
        while (!q.empty()) {
            unordered_set<int> visited;
            for (int i = q.size(); i > 0; --i) {
                int node = q.front(); q.pop();
                for (auto t : g[node]) {
                    if (dist[t.first] > dist[node] + t.second) {
                        dist[t.first] = dist[node] + t.second;
                        if (!visited.count(t.first)) {
                            visited.insert(t.first);
                            q.push(t.first);
                        }
                    }
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= N; ++i) {
            res = max(res, dist[i]);
        }
        return res == INT_MAX ? -1 : res;
    }
};

Bellman-Ford算法近似于暴力解法,暴力美学,针对所有的点,对存在的边都进行遍历一次,对已经连接到K点的u节点进行松弛操作。

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        int res = 0;
        vector<int> dist(N + 1, INT_MAX);
        dist[K] = 0;
        for (int i = 1; i < N; ++i) {
            for (auto time : times) {
                int u = time[0], v = time[1], w = time[2];
                if (dist[u] != INT_MAX && dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                }
            }
        }
        for (int i = 1; i <= N; ++i) {
            res = max(res, dist[i]);
        }
        return res == INT_MAX ? -1 : res;
    }
};

上面内容时间:2020-05-13 18:53:48

更新时间:2020-8-2 16:38:26
时隔3个月再做此题。

下面采取的是dijkstra算法的标准写法,模板解题,相关的模板可以见这篇博客,关于图的最短路,对于无权图可以用变型的BFS解,层数对应的即是最短路长度(可以把无权图等同成权值为1的有权图来看),但是对于有权图,用BFS水滴纹波来解就不太合适,因为每层向外延展的路径不等价(水纹荡漾开来的径向距离不等价),对于有权图只能采取dijkstra算法(单源最短路),Floyed算法(多源最短路)

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        vector<int> dist(N + 1, INT_MAX);
        vector<vector<pair<int, int>>> e(N + 1);
        for (auto &t : times) {
            e[t[0]].push_back(make_pair(t[1], t[2]));
        }
        vector<bool> visited(N + 1, false);
        dist[K] = 0;
        while (1) {
            int mindis = INT_MAX, minidx = -1;
            for (int i = 1; i <= N; ++i) {
                if (visited[i] == false) {
                    if (mindis > dist[i]) {
                        mindis = dist[i];
                        minidx = i;
                    }
                }
            }
            if (minidx == -1) break;
            visited[minidx] = true;
            for (int i = 0; i < e[minidx].size(); ++i) {
                int u = e[minidx][i].first, dis = e[minidx][i].second;
                if (visited[u] ==  false) {
                    if (dist[u] > dist[minidx] + dis) {
                        dist[u] = dist[minidx] + dis;
                    }
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= N; ++i) {
            if (dist[i] == INT_MAX) return -1;
            res = max(res, dist[i]);
        }
        return res;
    }
};

684. 冗余连接

原题链接

解题思路: 本题本质上是判断图中是否成环,不过用并查集解题能恰好回避此问题,如果能想到用并查集解此题,估计解题思路基本就出来了,具体的是,在访问边数组的同时构建并查集,若发现某个边对应的两个节点查询到的parent相同,则说明通过之前访问的边已经构建出这两个节点间的通路,而此次访问的是两节点间的直接通路,说明成环。此题的难点是如何通过图的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值