Problem: Course Schedule IV

There are a total of `numCourses` courses you have to take, labeled from `0`
to `numCourses - 1`. You are given an array `prerequisites` where
`prerequisites[i] = [ai, bi]` indicates that you must take course `ai` first
if you want to take course `bi`.

* For example, the pair `[0, 1]` indicates that you have to take course `0` before you can take course `1`.

Prerequisites can also be indirect. If course `a` is a prerequisite of course
`b`, and course `b` is a prerequisite of course `c`, then course `a` is a
prerequisite of course `c`.

You are also given an array `queries` where `queries[j] = [uj, vj]`. For the
`jth` query, you should answer whether course `uj` is a prerequisite of course
`vj` or not.

Return a boolean array `answer`, where `answer[j]` is the answer to the `jth`
query.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]:
    graph = [[] for _ in range(numCourses)]
    isPrerequisite = [[False] * numCourses for _ in range(numCourses)]

    for u, v in prerequisites:
      graph[u].append(v)

    for i in range(numCourses):
      self._dfs(graph, i, isPrerequisite[i])

    return [isPrerequisite[u][v] for u, v in queries]

  def _dfs(self, graph: List[List[int]], u: int, used: List[bool]) -> None:
    for v in graph[u]:
      if used[v]:
        continue
      used[v] = True
      self._dfs(graph, v, used)


Java solution:
class Solution {
  public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
    List<Boolean> ans = new ArrayList<>();
    List<Integer>[] graph = new List[numCourses];

    for (int i = 0; i < numCourses; ++i)
      graph[i] = new ArrayList<>();

    for (int[] prerequisite : prerequisites) {
      final int u = prerequisite[0];
      final int v = prerequisite[1];
      graph[u].add(v);
    }

    // isPrerequisite[i][j] := true if course i is a prerequisite of course j
    boolean[][] isPrerequisite = new boolean[numCourses][numCourses];

    // DFS from every course.
    for (int i = 0; i < numCourses; ++i)
      dfs(graph, i, isPrerequisite[i]);

    for (int[] query : queries) {
      final int u = query[0];
      final int v = query[1];
      ans.add(isPrerequisite[u][v]);
    }

    return ans;
  }

  public void dfs(List<Integer>[] graph, int u, boolean[] used) {
    for (final int v : graph[u]) {
      if (used[v])
        continue;
      used[v] = true;
      dfs(graph, v, used);
    }
  }
}


C++ solution:
class Solution {
 public:
  vector<bool> checkIfPrerequisite(int numCourses,
                                   vector<vector<int>>& prerequisites,
                                   vector<vector<int>>& queries) {
    vector<bool> ans;
    vector<vector<int>> graph(numCourses);
    // isPrerequisite[i][j] := true if course i is a prerequisite of course j
    vector<vector<bool>> isPrerequisite(numCourses, vector<bool>(numCourses));

    for (const vector<int>& prerequisite : prerequisites) {
      const int u = prerequisite[0];
      const int v = prerequisite[1];
      graph[u].push_back(v);
    }

    // DFS from every course.
    for (int i = 0; i < numCourses; ++i)
      dfs(graph, i, isPrerequisite[i]);

    for (const vector<int>& query : queries) {
      const int u = query[0];
      const int v = query[1];
      ans.push_back(isPrerequisite[u][v]);
    }

    return ans;
  }

  void dfs(const vector<vector<int>>& graph, int u, vector<bool>& used) {
    for (const int v : graph[u]) {
      if (used[v])
        continue;
      used[v] = true;
      dfs(graph, v, used);
    }
  }
};