leetcode207:课程表

题目链接

leetcode

题目描述

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai必须 先学习课程 bi 。例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

C++ 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

/*
深度优先搜索 DFS

遍历图结构,就可以判断环。
若遍历过程中发现下一个即将遍历的节点已被标记为 true,
则说明遇到了环。
*/
class Solution_0 {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
// 邻接矩阵存储图结构
vector<vector<int>> graph(numCourses);
for (const auto& edge : prerequisites) {
int from = edge[1], to = edge[0];
graph[from].push_back(to);
}

path.resize(numCourses, false);
visited.resize(numCourses, false);
// 遍历图中所有节点
for (int i = 0; i < numCourses; i++) {
dfs(graph, i);
}

// 若不存在环,则可以完成所有课程
return !hasCycle;
}

void dfs(vector<vector<int>>& graph, int s) {
if (path[s]) {
hasCycle = true; // 存在环
}
if (visited[s] || hasCycle) {
return; // 已找到环,结束
}

// 先序遍历位置
visited[s] = true;
path[s] = true;
for (int t : graph[s]) {
dfs(graph, t);
}
// 后序遍历位置
path[s] = false;
}

private:
vector<bool> path; // 记录当前路径上的节点
vector<bool> visited; // 记录已经遍历的节点,防止走回头路
bool hasCycle = false; // 记录图中是否有环
};

/*
广度优先搜索 BFS
*/
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses); // 邻接矩阵存储图结构
vector<int> inDegree(numCourses); // 每个点的入度

for (const auto& edge : prerequisites) {
int from = edge[1], to = edge[0];
graph[from].push_back(to);
inDegree[to]++;
}

// 初始化队列中的节点
queue<int> q;
for (int i = 0; i < numCourses; i++) {
// 若节点 i 没有入度,则作为拓扑排序的起点,加入队列
if (inDegree[i] == 0) {
q.push(i);
}
}

int count = 0; // 记录遍历节点的个数
// BFS 循环
while (!q.empty()) {
int cur = q.front(); q.pop();
count++;

// 删除边时,弹出节点 cur 并将入度 -1
for (int next : graph[cur]) {
inDegree[next]--;
if (inDegree[next] == 0) {
// 若入度变为 0,则说明 next 依赖的节点都已被遍历
q.push(next);
}
}
}

// 若所有节点都被遍历过,则说明不存在环
return count == numCourses;
}
};

// 辅助函数:打印二维数组
void printArray(const vector<vector<int>>& nums) {
cout << "[";
for (size_t i = 0; i < nums.size(); i++) {
cout << "[";
for (size_t j = 0; j < nums[i].size(); j++) {
cout << nums[i][j];
if (j != nums[i].size() - 1) cout << ",";
}
cout << "]";
if (i != nums.size() - 1) cout << ",";
}
cout << "]" << endl;
}

int main() {
Solution solution;
vector<int> num_cases = {
2, 2
};
vector<vector<vector<int>>> course_cases = {
{{1,0}},
{{1,0},{0,1}}
};

for (int i = 0; i < num_cases.size(); i++) {
int numCourses = num_cases[i];
vector<vector<int>> prerequisites = course_cases[i];

cout << "Input: numCourses = " << numCourses;
cout << ", prerequisites = [";
printArray(prerequisites);

// 判断是否可能完成所有课程的学习
bool result = solution.canFinish(numCourses, prerequisites);
cout << "Output: " << (result ? "true" : "false") << endl;
cout << "--------------------------" << endl;
}

return 0;
}

leetcode207:课程表
https://lcf163.github.io/2024/04/20/leetcode207:课程表/
作者
乘风的小站
发布于
2024年4月20日
许可协议