#Week3
Graph
question source: Course Schedul
##question description
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.
Example 1:
Input: 2, [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
Example 2:
Input: 2, [[1,0],[0,1]]
Output: false
Explanation: 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.
Note:
1. The input prerequisites is a graph represented by a list of edges,
not adjacency matrices. Read more about how a graph is represented.
2. You may assume that there are no duplicate edges in the input
prerequisites.
这周学习了图,这是一个有向图类型的题目,学生要想学一门课,可能要必须先学习另一门课,理解题意之后就知道这题实际上是要求我们判断有向图是否有环,如果有环,就不可能完成所有课程。在教材第105页讲了一个有向无环图的性质,每个有向无环图至少含有一个源点和一个汇点,根据源点存在性的保证,给出一种线性化的算法:找到一个源点,输出它,然后将它从图中删除,重复以上过程直至图为空。 就利用此算法,先假设它是有向无环图,如果图不为空,说明不是。
删除了源点之后,源点所指的点的入度要相应地减少。
代码如下
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
vector< vector<int>> graph(numCourses);
int degrees[numCourses];
memset(degrees, 0, sizeof(degrees));
//[0,1] 1->0 have to finish 1 first
for(auto i = prerequisites.begin(); i < prerequisites.end(); i++){
int x = (*i).first;
int y = (*i).second;
graph[y].push_back(x);
degrees[x]++;
}
int i,j,k;
for(i = 0; i < numCourses; i++){
for(j = 0; j < numCourses; j++){
if(degrees[j] == 0) break;
}
if(j == numCourses) return false;
degrees[j] --;
for(auto val : graph[j]){
degrees[val] --;
}
}
return true;
}
};
开始的时候我是用二维数组来保存图的,然后一直出错,原因是不能分配这么大的空间,于是就改成了用vector< vector> graph(numCourses)的形式来储存图。这样更节省空间,而且更快。
question source: 升级版
这一题要求输出线性化的序列,在前面的代码里保存一下源点访问的顺序就行了,如果不符合,则返回空数组。
代码如下
class Solution {
public:
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
vector< vector<int>> graph(numCourses);
vector<int> answer;
int degrees[numCourses];
memset(degrees, 0, sizeof(degrees));
//[0,1] 1->0 have to finish 1 first
for(auto i = prerequisites.begin(); i < prerequisites.end(); i++){
int x = (*i).first;
int y = (*i).second;
graph[y].push_back(x);
degrees[x]++;
}
bool tag = true;
int i,j,k;
for(i = 0; i < numCourses; i++){
for(j = 0; j < numCourses; j++){
if(degrees[j] == 0) break;
}
if(j == numCourses) {
tag = false;
break;
}
degrees[j] --;
answer.push_back(j);
for(auto val : graph[j]){
degrees[val] --;
}
}
if(tag){
return answer;
}else{
vector<int> a;
return a;
}
}
};
书上还有另一种方法判断是否为有向无环图还可以构建DFS森林,有向无环图是不含有回边的。