20230719-复习-拓扑排序

30 阅读1分钟

从今天开始复习图论专题,从拓扑排序开始,后面接并查集、最短路、迷宫等专题。图论有的题思路并不复杂,但代码基本上都比较长,比较考验熟练度和模板准备充分不充分。

拓扑排序算是图论里比较简单的,总体思路类似剥洋葱,一层一层剥掉入度/出度为0的节点。

leetcode-207 课程表

判断可不可行本质上是在图中找环。如果存在环,那么环中所有节点在任意时刻的入读都不会降至0,那么按照队列为空的循环终止条件,最终遍历到的节点数必然会少于课程总数。如果没有环则二者应相等。

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<int> in_degree(numCourses);
        vector<vector<int>> out_degree(numCourses);
        for(auto& i : prerequisites){
            int a = i[0], b = i[1];
            ++in_degree[a];
            out_degree[b].push_back(a);
        }
        deque<int> queue;
        for(int i = 0; i < numCourses; ++i){
            if(in_degree[i] == 0) queue.push_back(i);
        }
        int cnt = 0;
        while(!queue.empty()){
            ++cnt;
            int course = queue.front();
            queue.pop_front();
            vector<int> this_pre = out_degree[course];
            for(int i : this_pre){
                --in_degree[i];
                if(in_degree[i] == 0) queue.push_back(i);
            }
        }
        return cnt == numCourses;
    }
};

leetcode-802 找到最终的安全状态

这题类似反向的拓扑排序。经典拓扑排序剥掉入度为0的节点,这题需要剥掉出度为0的节点。画一下每层剥完之后的图能看出,按照每层剥掉出度为0的节点,等价于按照bfs方式遍历到每个节点到终端节点可能的路径(同样还可以写dfs,但写法就不一样了)。

class Solution {
public:
    vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> out_degree(n);
        vector<int> ans;
        for(int i = 0; i < n; ++i) out_degree[i] = graph[i].size();
        vector<vector<int>> in_nodes(n);
        for(int i = 0; i < n; ++i){
            for(int out : graph[i]) in_nodes[out].push_back(i);
        }
        deque<int> q;
        for(int i = 0; i < n; ++i){
            if(out_degree[i] == 0){
                q.push_back(i);
                ans.push_back(i);
            }
        }
        while(!q.empty()){
            int node = q.front();
            q.pop_front();
            vector<int>& this_in = in_nodes[node];
            for(int in : this_in){
                --out_degree[in];
                if(out_degree[in] == 0){
                    q.push_back(in);
                    ans.push_back(in);
                }
            }
        }
        sort(ans.begin(), ans.end());
        return ans;
    }
};