题目描述:
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.
程序代码:
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
map<int, vector<int>> m;
// 将课程转化为图,用邻接表表示,m[t]中为完成课程t后才能进行的课程
for (int i = 0; i < prerequisites.size(); i++) {
m[prerequisites[i].second].push_back(prerequisites[i].first);
}
// 用拓扑排序的思想
// 用向量记录每个顶点i的入度
vector<int> v(numCourses, 0); // numCourses个向量,初始化为0
for (int i = 0; i < numCourses; i++) {
for (int j = 0; j < m[i].size(); j++) {
v[m[i][j]]++;
}
}
// 遍历numCourses次
for (int n = 0; n < numCourses; n++) {
// 找到入度为0的点
for (int i = 0; i < numCourses; i++) {
// 若点i入度为0
if (v[i] == 0) {
v[i] = -1; // 标记为-1,表示将该点去掉
// 该点的边全部去掉,相应点的入度都-1
for (int j = 0; j < m[i].size(); j++) {
v[m[i][j]]--;
}
}
}
}
// 若还有入度不为0或标记为-1的点,则不是DAG,返回false. 否则返回true
for (int i = 0; i < numCourses; i++) {
if (v[i] != 0 && v[i] != -1) {
return false;
}
}
return true;
}
};
本题主要是有关图和拓扑排序算法的问题。
先理清题意。给出0到n-1编号的课程,并给出一系列数对[x,y],表示要上x课程需要先完成y课程,最后需要判断是否能够完成所有课程。根据题意,可以使用拓扑排序的思想来解决这个问题。
首先将课程转化为图,使用邻接表来进行表示(这里用到了STL库中的map来实现邻接表,由整数 t 映射到向量m[t],m[t]中为完成课程 t 后才能进行的课程)。将课程转化为图的表示后,再通过遍历邻接表,用一个向量 v 来记录每个顶点的入度。接着,再对邻接表遍历numCourses次,每一次都找到入度为0的点 i, 将其入度v[i] 标记为-1(表示将该点从图中去掉),并将该点出发的边全部去掉,即这些边指向的点的入度都减去1. 这样操作过后,若还有入度不为0或标记为-1的点,则不是DAG,返回false. 否则返回true。
通过本题,我很好的复习了本周所学的图及拓扑排序的有关内容。对于这些有关活动先后顺序的题目,可以考虑一下是否可以使用拓扑排序来解答。