CSP认证的第三题遇到了判断环的问题,当时用了dfs求解,样例跑对了,可是还是拿不到后面50分,有可能是找环的逻辑不太对。
因此上LeetCode刷了这道判断有向图是否有环的题。
题目描述
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-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。这是不可能的。
提示:
- 输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
- 你可以假定输入的先决条件中没有重复的边。
- 1 <= numCourses <= 10^5
思路
这道题我们需要将每一门课看成一个节点,如果想要学习课程 A 之前必须完成课程B,那么我们从B到A连接一条有向边,如果最终图里出现了环,就意味着两个课程是彼此的先决条件,显然不可能。
可以使用拓扑排序和dfs深度优先遍历两种方法解决:
(1)拓扑排序
拓扑排序:给定一个包含 n 个节点的有向图 G,我们给出它的节点编号的一种排列,如果满足:对于图 G 中的任意一条有向边 (u, v),u 在排列中都出现在 v 的前面。
根据上述的定义,我们可以得出两个结论:
因此我们只需要可以进行以下算法流程:
- 将所有入度为0的结点入队列
- 当队列不为空时,取出栈顶元素,出队,将被其指向的结点的入度减为0,如果有某个结点的入度也变为0,则将该结点入队
- 重复步骤2,直到队列为空
- 判断是否仍有入度不为0的结点,若有则存在环,若无则不存在环
需要注意的是这道题一开始是保存边,而不是以邻接表或者邻接矩阵的形式保存,因此要自行转换一下。
代码如下:
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int> > graph(numCourses);//邻接表
vector<int> <