コーススケジュールII - トポロジカルソート - DFS・BFSによる解法

問題概要

0からnumCourses-1までの整数で表される複数のコースが存在します。配列prerequisitesの各要素prerequisites[i] = [ai, bi]は、コースaiを受講する前にbiを完了する必要があることを示します。

すべてのコースを受講可能な順序を返してください。複数の有効な順序が存在する場合は、そのいずれかを返します。不可能な場合は空配列を返します。

例1

入力: numCourses = 2, prerequisites = [[1,0]]
出力: [0,1]

例2

入力: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
出力: [0,2,1,3]

解法アプローチ

  • 深さ優先探索(DFS)によるトポロジカルソート
  • 幅優先探索(BFS)を用いた Kahn's アルゴリズム

コード実装

DFSによる解法


class DfsSolver {
private:
    std::vector adjacencyList;
    std::vector<int> status;
    std::vector<int> order;
    bool isAcyclic = true;

    void depthFirstSearch(int node) {
        status[node] = 1; // 探索中
        for (int neighbor : adjacencyList[node]) {
            if (status[neighbor] == 0) {
                depthFirstSearch(neighbor);
                if (!isAcyclic) return;
            } else if (status[neighbor] == 1) {
                isAcyclic = false;
                return;
            }
        }
        status[node] = 2; // 完了
        order.push_back(node);
    }

public:
    std::vector<int> solve(int numCourses, std::vector& requirements) {
        adjacencyList.resize(numCourses);
        status.resize(numCourses);
        
        for (const auto& req : requirements) {
            adjacencyList[req[1]].push_back(req[0]);
        }

        for (int i = 0; i < numCourses && isAcyclic; ++i) {
            if (status[i] == 0) {
                depthFirstSearch(i);
            }
        }

        if (!isAcyclic) return {};
        std::reverse(order.begin(), order.end());
        return order;
    }
};

BFSによる解法


class BfsSolver {
private:
    std::vector adjacencyList;
    std::vector<int> indegree;
    std::vector<int> result;

public:
    std::vector<int> solve(int numCourses, std::vector& requirements) {
        adjacencyList.resize(numCourses);
        indegree.resize(numCourses);
        
        for (const auto& req : requirements) {
            adjacencyList[req[1]].push_back(req[0]);
            indegree[req[0]]++;
        }

        std::queue<int> zeroIndegree;
        for (int i = 0; i < numCourses; ++i) {
            if (indegree[i] == 0) {
                zeroIndegree.push(i);
            }
        }

        while (!zeroIndegree.empty()) {
            int current = zeroIndegree.front();
            zeroIndegree.pop();
            result.push_back(current);
            
            for (int neighbor : adjacencyList[current]) {
                if (--indegree[neighbor] == 0) {
                    zeroIndegree.push(neighbor);
                }
            }
        }

        return (result.size() == numCourses) ? result : std::vector<int>{};
    }
};

タグ: トポロジカルソート 深さ優先探索 幅優先探索 グラフアルゴリズム C++実装

5月30日 02:57 投稿