LeetCode //C - 207. 수업일정

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;
}

おすすめ

転載: blog.csdn.net/navicheung/article/details/133265740