Course Schedule Series
Course Schedule I: http://blog.youkuaiyun.com/Arcome/article/details/53790947
Course Schedule II: http://blog.youkuaiyun.com/Arcome/article/details/53791005
Problem
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 a list of prerequisite pairs,
is it possible for you to finish all courses?
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices.
Read more about how a graph is represented.
Hints:
- This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
- Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
- Topological sort could also be done via BFS.
Example
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0,
and to take course 0 you should also have finished course 1. So it is impossible.
Algorithm
整理一下题意:给定一组课程,课程之间有先修或后修的关系,要求判断能否修完给定的全部课程。
输入数据格式:给定整数numCourses和向量prerequisites:整数numCourses表示所有课程的数量;向量prerequisites包含一组pair格式的数据,如pair(a,b)表示修课程a前需要先修课程b。
可以抽象为图问题。numCourses表示图中的点数,向量prerequisites的每个元素都是一个pair,pair(a,b)由b指向a的一条边。于是可以得到一个有向图G。题目要求判断能否修完所有课程,即判断能否对所有点进行拓扑排序。若能对图G中所有点作拓扑排序,说明G中所有点都有前后关系,即不存在环。于是问题可以转化为判断图G是否存在环。
下面给出判断图G是否存在环的算法。使用到的数据结构为向量和队列。
先由输入数据建一张图,以邻接表进行存储。向量graph的每个元素graph[i]表示与节点i指向的所有节点的情况,如graph[i][j]存储了节点i指向的某个点的值。
建立邻接表过程中,同时更新每个点的入度。当某个点加入graph[i]向量时,该点的入度加一。
将图中所有入度为0的点加入到队列q中,作为遍历的起点。
若队列q非空,则取出队首元素,表示从图中删去该节点。由于删去了该节点,所以需要更新图中队首节点指向的节点的入度。更新后,若节点的入度为0,则加入队列。
重复步骤4直到队列为空。此时,由于图中所有入度为0的节点已通过拓扑排序的过程删去,故剩余的图为空图或环。此时再判断一次所有点的入度,若存在点入度不为0,说明剩余图中存在环,即原图包含环,于是不能修完所有课程,返回false。若所有节点入度均为0,说明剩余图为空图,不包含环,于是可以修完所有课程,返回true。
代码如下。
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
vector<vector<int>> graph(numCourses,vector<int> (0));
vector<int> in(numCourses,0);
for(int i=0;i<prerequisites.size();i++){
graph[prerequisites[i].second].push_back(prerequisites[i].first);
in[prerequisites[i].first]++;
}
queue<int> q;
for(int i=0;i<in.size();i++){
if(in[i]==0) q.push(i);
}
while(!q.empty()){
int p=q.front();
q.pop();
for(int i=0;i<graph[p].size();i++){
in[graph[p][i]]--;
if(in[graph[p][i]]==0) q.push(graph[p][i]);
}
}
for(int i=0;i<in.size();i++){
if(in[i]!=0) return false;
}
return true;
}
};