广度优先遍历+拓扑排序--检测是否存在环
拓扑排序:1. 所有入度为0的顶点加入队列
2. 取出队列中的一个顶点,将以该顶点为出度的边删除
3. 查看删除这条边后,以这条边为入度的顶点的入度是否为0,如果为0加入队列
4. 如果队不为空,循环遍历1-3
如果所有顶点的入度都为0那么说明没有环,如果存在入度不为0的点,那么说明存在环。
该题是典型的拓扑排序题,只需要检测是否存在环即可,如果不存在返回true,如果存在返回false
class Solution {
public:
/*要想学完所有课程:1.不能有回路(第二个值不能遍历过
遍历有向无环图,看图中是否有环,如果没有环怎返回true,否则返回false
拓扑排序:1. 寻找所有入度为0的顶点将其入队
*/
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
map<int,int> mp;
// 将所有顶点存入map中,入度置为0
for(int i=0;i<prerequisites.size();i++){
mp[prerequisites[i][0]] = 0;
mp[prerequisites[i][1]] = 0;
}
// 统计所有顶点的入度
for(int i=0;i<prerequisites.size();i++){
mp[prerequisites[i][1]]++; // 统计入度
}
queue<int> q;
// 将所有入度为0的顶点加入队列
for(auto m:mp){
if(m.second == 0){
q.push(m.first);
}
}
// 广度优先遍历
// 直到队列为空时,查看mp是否还有入度不为零的顶点,如果有说明存在环,如果没有则不存在环
while(!q.empty()){
int p = q.front(); // 选择第一个入列
q.pop();
// 将以该顶点入度的顶点入度数减一
for(int i=0;i<prerequisites.size();i++){
if(prerequisites[i][0] == p) {
mp[prerequisites[i][1]]--;
if(mp[prerequisites[i][1]] == 0){
// 该顶点为0了,将其入列
q.push(prerequisites[i][1]);
}
}
}
}
for(auto m:mp){
// cout<<m.first<<" "<<m.second<<endl;
if(m.second!=0){
return false;
}
}
return true;
}
};