[LeetCode] 207. 课程表(拓扑排序,BFS)

题目

现在你总共有 n 门课需要选,记为?0?到?n-1。

在选修某些课程之前需要一些先修课程。?例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?

示例 1:

输入: 2, [[1,0]]
输出: true
解释:?总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:

输入: 2, [[1,0],[0,1]]
输出: false
解释:?总共有 2 门课程。学习课程 1 之前,你需要先完成?课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
说明:

输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

  • 拓扑排序。

    • 数据结构:构建邻接表;入度数组;并使用队列维护待处理的入度为0的顶点;因为此处不需要拓扑序列,所以维护一个待放入拓扑序列顶点数即可,最后若待处理顶点数==0则说明可拓扑排序无环。
    • 做BFS,当队列不空:删掉入度为0的点,删掉该点出去的所有边;更新pointCnt;更新入度数组,将新的入度为0的点入队。
  • 此外,次题不考虑重边,输入的int[][] prerequisites 矩阵每一行存了一条弧的起点和终点。

相关

图的表示方法

1.邻接矩阵:矩阵m[i][j]表示i到j是否有弧/权重。有稀疏问题。
2.临接表:对图的每个节点,用一个单向链表列出从该节点出发的所有弧,链表中每个节点对应于一条出弧。
3.关联矩阵:矩阵每一行是一个点,每一列是描述一个弧(1表示弧的起点,-1表示弧的终点)。有稀疏问题。
4.弧表示法
5.星型表示法
很好的参考文章:https://blog.csdn.net/woaidapaopao/article/details/51732947

拓扑序列与拓扑排序

  • AOV网:通常,把顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
  • 在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。
  • 拓扑排序的另一个重要作用是可以判断有向图是否无环

拓扑排序算法流程(同时可以用来判断有向图是否无环

当还有入度为0的点未放入结果序列:

  • 1 选择一个入度为0的顶点并放入结果序列尾
  • 2 从网中删除此顶点及所有出边。
    结束后,若结果集中未包含全部点(即产生入度不为0的点无法放入),则说明图中有环,否则结果序列就是一个拓扑序列。

代码

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int pointCnt = numCourses;// 未放入拓扑序列的点的个数
        HashMap<Integer, List<Integer>> adjList = new HashMap<>();// 邻接表
        int[] inDegree = new int[numCourses];// 存放顶点入度
        LinkedList<Integer> pointQue = new LinkedList<>();// 存放当前待处理的入度为0的顶点

        for (int[] edge : prerequisites) {
            // 初始化邻接表
            List<Integer> tempList = adjList.getOrDefault(edge[0], new LinkedList<>());
            tempList.add(edge[1]);
            adjList.put(edge[0], tempList);

            // 初始化顶点入度数组
            inDegree[edge[1]]++;
        }

        // 入度为0的点放入队列
        for (int i = 0; i < numCourses; ++i) {
            if (inDegree[i] == 0) {
                pointQue.addLast(i);
            }
        }

        // 删掉入度为0的点,删掉关联的所有边;更新pointCnt;更新入度数组,将新的入度为0的点入队。
        while (!pointQue.isEmpty()) {
            int u = pointQue.removeFirst();
            pointCnt--;
            if (adjList.containsKey(u)) {//
                for (int v : adjList.get(u)) {
                    inDegree[v]--;
                    if (inDegree[v] == 0) {
                        pointQue.push(v);
                    }
                }
            }
        }

        return pointCnt == 0;
    }

参考链接

https://blog.csdn.net/qq_41713256/article/details/80805338

原文地址:https://www.cnblogs.com/coding-gaga/p/11745782.html

时间: 2024-10-10 04:41:53

[LeetCode] 207. 课程表(拓扑排序,BFS)的相关文章

Leetcode 207 课程表 (拓扑排序,判断有向图环)

定义一个队列Q,把入度为0的结点入队 若Q不为空,则取队首结点,删去所有从该点出发的边,并把这些边所到达结点的入度减一,若某个节点入度减为0,则将它入队 反复进行如上操作,直到队列为空.(当总的入队次数大于节点数时,跳出循环) 如果这时入过队的节点数恰好等于节点总数,则为有向无环图.否则有环. class Solution { public: static const int maxn = 10000; vector<int> gra[maxn]; int co = 0; int count[

LeetCode编程训练 - 拓扑排序(Topological Sort)

拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序(被依赖的排在前面),或给出排序结果. 最常用解决拓扑排序问题的方法是Kahn算法,步骤可以概括为: 1. 根据依赖关系,构建邻接矩阵或邻接表.入度数组 2. 取入度为0的数据(即不依赖其他数据的数据),根据邻接矩阵/邻接表依次减小依赖其的数据的入度 3. 判断减小后是否有新的入度为0的数据,继续进

Leetcode 207. 课程表

class Solution { public: struct GraphNode { int lable; vector<GraphNode*> neighbors; GraphNode(int x):lable(x){} }; bool DFS_graph(GraphNode* node, vector<int>& visit) { //正在访问 visit[node->lable] = 0; for(int i=0; i<node->neighbor

LeetCode 207. Course Schedule(拓扑排序)

题目 There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and

LeetCode 207. Course Schedule(拓扑排序-求有向图中是否存在环)

求有向图中是否有环. 法一:拓扑排序 用一个队列维护所有入度为0的节点,每次弹出一个节点v,查看从v可达的所有节点u; 将u的入读减一,若u的入度此时为0, 则将u加入队列. 在队列为空时,检查所有节点的入度,若所有节点入度都为0, 则存在这样的一个拓扑排序 -- 有向图中不存在环. 代码: class Solution { public: bool canFinish(int numCourses, vector<pair<int, int>>& prerequisite

LeetCode 207. Course Schedule(拓扑排序)

题目 题意:有n门课程,就是n个顶点,有m个对应关系:x,y,表示只有先上了y,才能上x.也就是x到y有一条有向边.问你求是否存在环. 题解:对于有向图求是否存在环,可以用拓扑排序,拓扑排序就是寻找入度为0的顶点,然后删去,并减少相邻点的入度,再寻找入度为0的点,直到所有顶点都删去,如果存在换,那么一定会有一些点是无法删除的. class Solution { public: vector<int> edge[10005]; int a[10005]; int b[10005]; int vi

LeetCode 210. Course Schedule II(拓扑排序-求有向图中是否存在环)

和LeetCode 207. Course Schedule(拓扑排序-求有向图中是否存在环)类似. 注意到,在for (auto p: prerequistites)中特判了输入中可能出现的平行边或自环. 代码: class Solution { public: vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) { // [0, {1, 2, 3}], me

bfs 拓扑排序 bnu Usoperanto

题目链接:http://acm.bnu.edu.cn/v3/problem_show.php?pid=39572 题目详细分析:http://talk.icpc-camp.org/d/127-jag-summer-2012-day-4-j-usoperanto 对于这个题目,自己的一点补充(bfs 拓扑排序):在建树的时候,每建立一条边,父亲节点出度+1,因此树叶子节点的出度是为0的(题解里说的入度其实就是在建边的时候父亲节点的出度):那么把所有出度为0的节点压入队列,然后计算这些出度为0的节点

图论 邻接链表存储 BFS DFS 拓扑排序

package Algorithms; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.Stack; public class Graphic { public static class Vertex{ public int num;//节点编号 public int weight;//边的权重 public Vertex next;//指向顶点的