题目描述:
题目链接:leetcode 207. 课程表
你这个学期必须选修 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 <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同
分析
经典拓扑排序模型。只要课程和课程间构成的有向图不存在环,则课程的安排是合理的。故此题用拓扑排序判断一下是否存在环即可。
C++ 代码
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
int n=prerequisites.size();
if(numCourses==1||n==0) return true; //只有一门课或者图为空则不存在环
vector<int>in(numCourses,0); //记录入度
vector<vector<int>>Graph(numCourses,vector<int>()); //存图
for(int i=0;i<n;i++)
{
int u=prerequisites[i][1];
int v=prerequisites[i][0];
in[v]++; //记录入度
Graph[u].push_back(v); //加边
}
int rest=numCourses; //记录入度不为0的点数
queue<int>q;
for(int i=0;i<numCourses;i++)
{
if(!in[i])
{
q.push(i);
rest--;
}
}
//bfs"删点"
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<Graph[u].size();i++)
{
int v=Graph[u][i];
in[v]--;
if(!in[v])
{
q.push(v);
rest--;
}
}
}
return rest==0;
}
};