Skip to content

2858. Minimum Edge Reversals So Every Node Is Reachable 👍

  • Time: $O(|V| + |E|)$
  • Space: $O(|V| + |E|)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Solution {
 public:
  vector<int> minEdgeReversals(int n, vector<vector<int>>& edges) {
    vector<int> ans(n);
    vector<vector<pair<int, bool>>> graph(n);
    vector<bool> seen(n);

    for (const vector<int>& edge : edges) {
      const int u = edge[0];
      const int v = edge[1];
      graph[u].emplace_back(v, /*isForward=*/true);
      graph[v].emplace_back(u, /*isForward=*/false);
    }

    vector<int> mem(n, -1);
    ans[0] = minEdgeReversals(graph, 0, seen, mem);
    seen = vector<bool>(n);
    dfs(graph, 0, seen, ans);
    return ans;
  }

 private:
  // Returns the minimum number of edge reversals so node u can reach every
  // node in its subtree.
  int minEdgeReversals(const vector<vector<pair<int, bool>>>& graph, int u,
                       vector<bool>& seen, vector<int>& mem) {
    if (mem[u] != -1)
      return mem[u];
    int res = 0;
    seen[u] = true;
    for (const auto& [v, isForward] : graph[u]) {
      if (seen[v])
        continue;
      seen[v] = true;
      res += minEdgeReversals(graph, v, seen, mem) + (isForward ? 0 : 1);
    }
    return mem[u] = res;
  }

  void dfs(const vector<vector<pair<int, bool>>>& graph, int u,
           vector<bool>& seen, vector<int>& ans) {
    seen[u] = true;
    for (const auto& [v, isForward] : graph[u]) {
      if (seen[v])
        continue;
      seen[v] = true;
      ans[v] = ans[u] + (isForward ? 1 : -1);
      dfs(graph, v, seen, ans);
    }
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Solution {
  public int[] minEdgeReversals(int n, int[][] edges) {
    int[] ans = new int[n];
    List<Pair<Integer, Boolean>>[] graph = new List[n];
    boolean[] seen = new boolean[n];

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

    for (int[] edge : edges) {
      final int u = edge[0];
      final int v = edge[1];
      graph[u].add(new Pair<>(v, /*isForward=*/true));
      graph[v].add(new Pair<>(u, /*isForward=*/false));
    }

    Integer[] mem = new Integer[n];
    ans[0] = minEdgeReversals(graph, 0, seen, mem);
    seen = new boolean[n];
    dfs(graph, 0, seen, ans);
    return ans;
  }

  // Returns the minimum number of edge reversals so node u can reach every
  // node in its subtree.
  private int minEdgeReversals(List<Pair<Integer, Boolean>>[] graph, int u, boolean[] seen,
                               Integer[] mem) {
    if (mem[u] != null)
      return mem[u];
    int res = 0;
    seen[u] = true;
    for (Pair<Integer, Boolean> pair : graph[u]) {
      final int v = pair.getKey();
      final boolean isForward = pair.getValue();
      if (seen[v])
        continue;
      seen[v] = true;
      res += minEdgeReversals(graph, v, seen, mem) + (isForward ? 0 : 1);
    }
    return mem[u] = res;
  }

  private void dfs(List<Pair<Integer, Boolean>>[] graph, int u, boolean[] seen, int[] ans) {
    seen[u] = true;
    for (Pair<Integer, Boolean> pair : graph[u]) {
      final int v = pair.getKey();
      final boolean isForward = pair.getValue();
      if (seen[v])
        continue;
      seen[v] = true;
      ans[v] = ans[u] + (isForward ? 1 : -1);
      dfs(graph, v, seen, ans);
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution:
  def minEdgeReversals(self, n: int, edges: list[list[int]]) -> list[int]:
    graph = [[] for _ in range(n)]

    for u, v in edges:
      graph[u].append((v, True))  # 1 means (u -> v)
      graph[v].append((u, False))  # 0 means (v <- u)

    seen = {0}

    @functools.lru_cache(None)
    def dp(u: int) -> int:
      """
      Returns the minimum number of edge reversals so node u can reach every
      node in its subtree.
      """
      res = 0
      for v, isForward in graph[u]:
        if v in seen:
          continue
        seen.add(v)
        res += dp(v) + (0 if isForward else 1)
      return res

    ans = [0] * n
    ans[0] = dp(0)

    def dfs(u: int) -> None:
      for v, isForward in graph[u]:
        if v in seen:
          continue
        seen.add(v)
        ans[v] = ans[u] + (1 if isForward else -1)
        dfs(v)

    seen = {0}
    dfs(0)
    return ans