赞
踩
目录
拓扑排序简单来说就是找到做事情的先后顺序(拓扑排序的结果可能不是唯一的)。
学习拓扑排序前先简单学习图的基本概念:
图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E),其中:
入度和出度
图中的度:所谓顶点的度(degree),就是指和该顶点相关联的边数。在有向图中,度又分为入度和出度。
邻接表
邻接表存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。
有向图邻接表存储
下面是拓扑排序的概念:
一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity)。在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。
对于有向图的拓扑排序,我们可以使用如下思路输出拓扑序(BFS 方式):
难度 中等
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 1
。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites
给出,其中 prerequisites[i] = [ai, bi]
,表示如果要学习课程 ai
则 必须 先学习课程 bi
。
[0, 1]
表示:想要学习课程 0
,你需要先完成课程 1
。请你判断是否可能完成所有课程的学习?如果可以,返回 true
;否则,返回 false
。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:true 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]] 输出:false 解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i]
中的所有课程对 互不相同- class Solution {
- public:
- bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
-
- }
- };
原问题可以转换成一个拓扑排序问题。用BFS 解决拓扑排序即可。
- class Solution {
- public:
- bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
- unordered_map<int, vector<int>> edges; // 领接表
- vector<int> in(numCourses, 0); // 存储每一个结点的入度
- for(auto& e : prerequisites) // 1. 建图
- {
- int a = e[0], b = e[1];; // b指向a
- edges[b].push_back(a);
- in[a]++;
- }
-
- queue<int> q; // 2. BFS解决拓扑排序
- for(int i = 0; i < numCourses; ++i)
- {
- if(in[i] == 0)
- q.push(i);
- }
- while(!q.empty()) // 层序遍历
- {
- int tmp = q.front();
- q.pop();
- for(auto& e : edges[tmp]) // 得到tmp指向的顶点, 删掉一个入度
- {
- in[e]--;
- if(in[e] == 0)
- q.push(e);
- }
- }
- for(auto& e : in) // 3. 判断是否有环
- {
- if(e != 0)
- return false;
- }
- return true;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。