算法——图论:拓扑排序

. - 力扣(LeetCode)

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

即图中不能有环。

注意邻接表和邻接矩阵的转换。

自己的解法:拓扑排序,找出每个节点前面节点的个数,不断遍历将值为零的访问。

类似广度优先搜索,不过不完全一样,未使用队列,时间复杂度较高。

复制代码
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if(prerequisites.size()==0)return true;
        vector<long long> pre(numCourses,0);
        vector<int> visited(numCourses,0);
        for(int i=0;i<prerequisites.size();i++)
        {
            int  a=prerequisites[i][0],b=prerequisites[i][1];
            pre[a]++;
        }
        int maxcou=numCourses;
        while(maxcou--)
        {
            for(int i=0;i<numCourses;i++)
            {
                if(visited[i]==0&&pre[i]==0)
                {
                    visited[i]=1;
                    for(int j=0;j<prerequisites.size();j++)
                    {
                        if(prerequisites[j][1]==i)
                        pre[prerequisites[j][0]]--;
                    }
                }
            }
        }
        for(int i=0;i<numCourses;i++)
        {
            if(visited[i]==0)return false;
        }        
        return true;
    }
};

注意:在while循环中判断条件为课程数量,即最多可能循环这么多次。考虑极端情况:

5->4->3->2->1,第一次到最后才找到5,第二次到最后才找到4,这样每次循环只能访问一个节点。需n次。若为1->2->3->4->5,则仅需一次即可访问全部节点。

题目中使用的是邻接矩阵,或者转换一下使用邻接表,会更方便。

官方题解:

1.深搜

复制代码
class Solution {
private:
    vector<vector<int>> edges;
    vector<int> visited;
    bool valid = true;

public:
    void dfs(int u) {
        visited[u] = 1;
        for (int v: edges[u]) {
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            }
            else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);
        }
        for (int i = 0; i < numCourses && valid; ++i) {
            if (!visited[i]) {
                dfs(i);
            }
        }
        return valid;
    }
};

2.广搜

使用一个队列;将邻接矩阵转化为邻接表。

复制代码
class Solution {
private:
    vector<vector<int>> edges;
    vector<int> indeg;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);
            ++indeg[info[0]];
        }

        queue<int> q;
        for (int i = 0; i < numCourses; ++i) {
            if (indeg[i] == 0) {
                q.push(i);
            }
        }

        int visited = 0;
        while (!q.empty()) {
            ++visited;
            int u = q.front();
            q.pop();
            for (int v: edges[u]) {
                --indeg[v];
                if (indeg[v] == 0) {
                    q.push(v);
                }
            }
        }

        return visited == numCourses;
    }
};
相关推荐
啊董dong2 分钟前
noi-2026年5月12号小测验
数据结构·c++·算法
不知名的忻3 分钟前
红黑树(简易版)
算法·红黑树
NQBJT5 分钟前
万字拆解 NeckFix:AI 脖子前倾检测的算法原理与工程实现
人工智能·算法
jaychouchannel9 分钟前
Python 常用排序算法详解
算法
数智工坊11 分钟前
【Inner Monologue论文阅读】: 首次将大语言模型嵌入机器人控制闭环,实现自我反思和动态行为调整
论文阅读·人工智能·算法·语言模型·机器人·无人机
为何创造硅基生物1 小时前
C 语言 typedef 结构体私有化
c语言·开发语言·算法
yzx9910131 小时前
递归算法入门:像俄罗斯套娃一样思考
人工智能·算法
心中有国也有家1 小时前
从零上手 CANN 学习中心:像逛技术便利店一样学昇腾
学习·算法·开源
oo哦哦1 小时前
搜索矩阵系统的最短路密码:用Dijkstra算法和网络流理论,解释为什么你做了1000个关键词,流量还不如别人30个
网络·算法·矩阵
Matlab程序猿小助手1 小时前
【MATLAB源码-第319期】基于matlab的帝王蝶优化算法(MBO)无人机三维路径规划,输出做短路径图和适应度曲线.
开发语言·算法·matlab