[leetcode] CourseSchedule

CourseSchedule

  • 問題描述:輸入一個n代表我們有N門課程,編碼成0-n-1, 然後給一系列課程的前置條件,問這樣安排課程是否合理。
  • 問題可以轉化成判斷圖中是否有環的問題。
    • 我們將每門課程看成一個節點。
    • 前置條件是條有向的邊。
    • 所有圖是有向圖。
    • 如果圖中存在環則前置課程必定存在衝突,否則則不衝突。
  • 是否存在環?
    • 解法1
      • 我們首先計算每個節點的入度。
      • 將所有入度爲0的節點加入隊列中
      • 依次遍歷隊列中的節點, 隊列爲空則退出
      • 針對每個節點,我們刪除其所有邊,並且對應節點的入度減1。
      • 如果最後所有節點都遍歷了,則沒有環,否則有環
    • 解法2
      • 我們利用dfs來遍歷。
      • 我們針對每個點有三個狀態0,1,2
        • 0 代表這個點還沒訪問
        • 1 代表正在訪問,當前連通分量還沒有訪問結束,如果碰到將要訪問的點是1,則代表有環
        • 2 代表該點已經訪問過,且該點所在的連通分量也訪問完成。
//
// Created by 樑棟 on 2019-05-12.
//
#include <vector>
#include <iostream>
using namespace std;
class Solution {
public:
    bool canFinishBase(int** graph, int n, int cur, int* visit, int* father){
        // 判斷是否存在環
        visit[cur] = 1;
        for(int i=0;i<n;i++){
            if(i!=cur && graph[cur][i] == 1){
                // 代表有邊
                // 如果剔除i->i,則father[cur] != i
                if(visit[i] == 1 && father[i] != cur){
                    return true;
                }else{
                    if(visit[i] == 0){
                        father[i] = cur;
                        if(canFinishBase(graph, n, i, visit, father))
                            return true;
                    }
                }
            }
        }
        visit[cur] = 2; // 代表該點訪問完成,下次訪問的話不會是1的狀態,說明應該是另一個連通分量
        return false;

    }
    bool canFinishV2(int numCourses, vector<vector<int>>& prerequisites){
        int** graph = new int*[numCourses];
        for(int i=0;i<numCourses;i++){
            graph[i] = new int[numCourses];
        }
        int n = numCourses;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                graph[i][j] = 0;
            }
        }
        for(auto v: prerequisites){
            graph[v[0]][v[1]] = 1; // first->second
        }
        int* father = new int[n];
        int* visit = new int[n];
        for(int i=0;i<n;i++){
            father[i] = -1;
            visit[i] = 0;
        }
        for(int i=0;i<n;i++)
            if(visit[i] == 0)
                if(canFinishBase(graph, n, i, visit, father)){
                    // 存在環
                    return false;
                }
        // 不存在環
        return true;

    }
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        int graph[numCourses][numCourses];
        memset(graph, 0, sizeof(graph));
        vector<int> rudu(numCourses);
        for(auto v: prerequisites){
            graph[v[0]][v[1]] = 1; // first->second
            rudu[v[1]] += 1;
        }
        int n = numCourses;

        // adjust whether existing circle
        vector<int> nodes;
        int count = 0;
        for(int i=0;i<numCourses;i++){
            if(rudu[i] == 0){
                // 入度爲0
                nodes.push_back(i);
                count += 1;
            }
        }
        while(!nodes.empty()){
            int cur_node = nodes.back();
            nodes.pop_back();
            for(int i=0;i<numCourses;i++){
                if(graph[cur_node][i] == 1){
                    graph[cur_node][i] = 0;
                    rudu[i] -= 1;
                    if(rudu[i] == 0){
                        nodes.push_back(i);
                        count += 1;
                    }
                }
            }
        }
        return count == numCourses;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章