207. 강좌일정
수강해야 하는 총 numCourses 강좌가 있으며 0부터 numCourses - 1까지 레이블이 지정됩니다. prerequisites[i] = [ai, bi]는 수강하려는 경우 먼저 bi 강좌를 수강해야 함을 나타내는 배열 전제 조건이 제공됩니다. 물론이지.
- 예를 들어, [0, 1] 쌍은 코스 0을 수강하려면 먼저 코스 1을 수강해야 함을 나타냅니다.
모든 과정을 완료할 수 있으면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.
예시 1:
입력: numCourses = 2, 전제 조건 = [[1,0]]
출력: true
설명: 총 2개 과정을 수강해야 합니다.
1과정을 수강하려면 0과정을 이수해야 하므로 가능합니다.
예 2:
입력: numCourses = 2, 전제 조건 = [[1,0],[0,1]]
출력: false
설명: 총 2개 과정을 수강해야 합니다.
1과목을 수강하려면 0과목을 이수해야 하고, 0과목을 수강하려면 1과목도 이수해야 하기 때문에 불가능합니다.
제약:
- 1 <= 강좌 수 <= 2000
- 0 <= 전제조건.길이 <= 5000
- 전제조건[i].length == 2
- 0 <= ai, bi < numCourses
- 모든 쌍의 전제조건[i]은 고유합니다.
보낸 사람: LeetCode
링크: 207. 강좌 일정
해결책:
아이디어:
1. 그래프 표현:
- 각 코스는 방향성 그래프의 노드로 표시됩니다.
- 각 전제 조건은 코스 a에서 코스 b로 향하는 가장자리로 표시되며, 이는 코스 b가 코스 a보다 먼저 수강되어야 함을 나타냅니다.
2. 주기 감지:
- 각 노드(과정)에 대해 DFS를 수행하여 인접한 노드(전제 조건)를 탐색합니다.
- DFS 중에 아직 처리 중인(VISITING) 노드를 다시 방문하는 경우 이는 그래프에 주기가 존재하므로 모든 과정을 완료할 수 없음을 의미합니다.
- 모든 노드를 탐색한 후 그래프에서 사이클이 발견되지 않으면 모든 코스를 완료할 수 있음을 의미합니다.
3. DFS 탐색:
- 각 노드에 대해 처리되는 동안 VISITING으로 표시하고 인접한 노드를 재귀적으로 탐색합니다.
- VISITING으로 표시된 노드를 다시 방문하면 주기가 감지되었음을 의미합니다.
- 인접한 노드를 모두 탐색한 후 해당 노드를 VISITED로 표시합니다.
4. 인접 목록:
- 그래프는 인접 목록을 사용하여 표현되며, 각 노드에 대해 인접 노드의 연결 목록이 유지됩니다.
암호:
#define NOT_VISITED 0
#define VISITING 1
#define VISITED 2
typedef struct Node {
int val;
struct Node* next;
} Node;
typedef struct Graph {
Node** adjList;
int* visited;
int numVertices;
} Graph;
Graph* createGraph(int numVertices) {
Graph* graph = (Graph*)malloc(sizeof(Graph));
graph->adjList = (Node**)malloc(numVertices * sizeof(Node*));
graph->visited = (int*)malloc(numVertices * sizeof(int));
graph->numVertices = numVertices;
for(int i = 0; i < numVertices; i++) {
graph->adjList[i] = NULL;
graph->visited[i] = NOT_VISITED;
}
return graph;
}
void addEdge(Graph* graph, int src, int dest) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->val = dest;
newNode->next = graph->adjList[src];
graph->adjList[src] = newNode;
}
bool dfs(Graph* graph, int vertex) {
if(graph->visited[vertex] == VISITING) return false; // Cycle detected.
if(graph->visited[vertex] == VISITED) return true; // Already visited.
graph->visited[vertex] = VISITING;
for(Node* neighbor = graph->adjList[vertex]; neighbor != NULL; neighbor = neighbor->next)
if(!dfs(graph, neighbor->val)) return false; // Cycle detected in the next vertex.
graph->visited[vertex] = VISITED;
return true;
}
bool canFinish(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize){
Graph* graph = createGraph(numCourses);
// Build adjacency list from prerequisites.
for(int i = 0; i < prerequisitesSize; i++)
addEdge(graph, prerequisites[i][0], prerequisites[i][1]);
// Run DFS from each vertex.
for(int i = 0; i < numCourses; i++)
if(graph->visited[i] == NOT_VISITED && !dfs(graph, i)) return false;
return true;
}