算法——图论:拓扑排序

. - 力扣(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;
    }
};
相关推荐
IT猿手几秒前
超多目标优化:基于导航变量的多目标粒子群优化算法(NMOPSO)的无人机三维路径规划,MATLAB代码
人工智能·算法·机器学习·matlab·无人机
Erik_LinX10 分钟前
算法日记25:01背包(DFS->记忆化搜索->倒叙DP->顺序DP->空间优化)
算法·深度优先
Alidme17 分钟前
cs106x-lecture14(Autumn 2017)-SPL实现
c++·学习·算法·codestepbystep·cs106x
小王努力学编程18 分钟前
【算法与数据结构】单调队列
数据结构·c++·学习·算法·leetcode
最遥远的瞬间20 分钟前
15-贪心算法
算法·贪心算法
维齐洛波奇特利(male)1 小时前
(动态规划 完全背包 **)leetcode279完全平方数
算法·动态规划
项目申报小狂人2 小时前
改进收敛因子和比例权重的灰狼优化算法【期刊论文完美复现】(Matlab代码实现)
开发语言·算法·matlab
让我们一起加油好吗2 小时前
【排序算法】六大比较类排序算法——插入排序、选择排序、冒泡排序、希尔排序、快速排序、归并排序【详解】
c语言·算法·排序算法
夏末秋也凉3 小时前
力扣-贪心-53 最大子数组和
数据结构·算法·leetcode
liruiqiang054 小时前
机器学习 - 投票感知器
人工智能·算法·机器学习