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?
For 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.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices.
思路:
此题可抽象为有向图中的环检测问题。常规解法为构建邻接矩阵或邻接链表后通过拓扑排序检测有向图中是否存在环路来解决。若存在环路说明这个小朋友悲剧了,即将面临辍学的危机,否则,小朋友就可以任性的选课直到毕业(然而事实上即使能顺利毕业也并没有什么*用)。
在这里使用了两个set容器数组来构建图(考虑到也许会有重复输入等情况,还有就是懒 - -!),随后进行拓扑排序求得结果。
1 class Solution { 2 public: 3 bool canFinish(int numCourses, vector<pair<int, int> >& prerequisites) { 4 5 const int n = numCourses; 6 int cnt = 0; 7 8 set<int> sets[n], grap[n]; 9 queue<int> Queue;//队列,拓扑排序必备 10 11 //从给定的输入中构建图,sets[i]表示学习课程i后才能继续学习的后置课程的集合 12 //grap[i]表示学习课程i所必须的前置课程的集合(入度) 13 vector<pair<int, int> >::iterator it = prerequisites.begin(); 14 for(; it != prerequisites.end(); it++) 15 { 16 sets[(*it).second].insert((*it).first); 17 grap[(*it).first].insert((*it).second); 18 } 19 20 //将不需要前置课程的课程(入度为0的课程)压入队列 21 for(int i = 0; i < n; i++) 22 if(grap[i].size() == 0) 23 Queue.push(i); 24 25 while(!Queue.empty()) 26 { 27 //取出队首的课程 28 int cur = Queue.front(); 29 Queue.pop(); 30 31 //遍历当前课程(cur)的后置课程集合 32 //在每一个后置课程(*it)的前置课程的集合(grap[*it])中去掉当前课程 33 //若去掉当前课程后该课程的前置课程集合为空,则将其压入队列 34 set<int>::iterator it = sets[cur].begin(); 35 for(; it != sets[cur].end(); it++) 36 { 37 grap[*it].erase(cur); 38 if(grap[*it].size() == 0) 39 Queue.push(*it); 40 } 41 cnt++;//统计共拓扑出了多少课程 42 } 43 44 //若拓扑出的课程数等于总课程数,说明无环,return true,反之,return false 45 return cnt == n ? 1 : 0; 46 } 47 };