Reachable Nodes In Subdivided Graph

hard graph dijkstra heap

Problem

Start at node 0 of an undirected graph; edge [u, v, cnt] is subdivided into cnt extra nodes forming a chain of length cnt + 1. With at most maxMoves moves (each move steps to an adjacent node), count how many nodes — original plus subdivided — are reachable. Run Dijkstra maximizing the moves remaining at each original node.

Inputedges = [[0,1,10],[0,2,1],[1,2,2]], maxMoves = 6, n = 3
Output13
3 original nodes + 7 + 1 + 2 subdivided nodes reached.

import heapq

def reachable_nodes(edges, max_moves, n):
    adj = [dict() for _ in range(n)]
    for u, v, cnt in edges:
        adj[u][v] = adj[v][u] = cnt
    heap = [(-max_moves, 0)]
    seen, used, ans = {}, {}, 0
    while heap:
        moves, u = heapq.heappop(heap)
        moves = -moves
        if u in seen:
            continue
        seen[u] = moves
        ans += 1
        for v, cnt in adj[u].items():
            used[(u, v)] = min(moves, cnt)
            nxt = moves - cnt - 1
            if v not in seen and nxt >= 0:
                heapq.heappush(heap, (-nxt, v))
    for u, v, cnt in edges:
        ans += min(cnt, used.get((u, v), 0) + used.get((v, u), 0))
    return ans
function reachableNodes(edges, maxMoves, n) {
  const adj = Array.from({ length: n }, () => new Map());
  for (const [u, v, cnt] of edges) { adj[u].set(v, cnt); adj[v].set(u, cnt); }
  const heap = [[maxMoves, 0]];  // by moves remaining (pop max each loop)
  const seen = new Map(), used = new Map();
  let ans = 0;
  while (heap.length) {
    heap.sort((a, b) => b[0] - a[0]);
    const [moves, u] = heap.shift();
    if (seen.has(u)) continue;
    seen.set(u, moves); ans++;
    for (const [v, cnt] of adj[u]) {
      used.set(u + "," + v, Math.min(moves, cnt));
      const nxt = moves - cnt - 1;
      if (!seen.has(v) && nxt >= 0) heap.push([nxt, v]);
    }
  }
  for (const [u, v, cnt] of edges) {
    const a = used.get(u + "," + v) || 0, b = used.get(v + "," + u) || 0;
    ans += Math.min(cnt, a + b);
  }
  return ans;
}
int reachableNodes(int[][] edges, int maxMoves, int n) {
    Map<Integer,Integer>[] adj = new HashMap[n];
    for (int i = 0; i < n; i++) adj[i] = new HashMap<>();
    for (int[] e : edges) { adj[e[0]].put(e[1], e[2]); adj[e[1]].put(e[0], e[2]); }
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[0] - a[0]);
    pq.add(new int[]{maxMoves, 0});
    Map<Integer,Integer> seen = new HashMap<>();
    Map<String,Integer> used = new HashMap<>();
    int ans = 0;
    while (!pq.isEmpty()) {
        int[] top = pq.poll(); int moves = top[0], u = top[1];
        if (seen.containsKey(u)) continue;
        seen.put(u, moves); ans++;
        for (var e : adj[u].entrySet()) {
            int v = e.getKey(), cnt = e.getValue();
            used.put(u + "," + v, Math.min(moves, cnt));
            int nxt = moves - cnt - 1;
            if (!seen.containsKey(v) && nxt >= 0) pq.add(new int[]{nxt, v});
        }
    }
    for (int[] e : edges) {
        int a = used.getOrDefault(e[0] + "," + e[1], 0);
        int b = used.getOrDefault(e[1] + "," + e[0], 0);
        ans += Math.min(e[2], a + b);
    }
    return ans;
}
int reachableNodes(vector<vector<int>>& edges, int maxMoves, int n) {
    vector<map<int,int>> adj(n);
    for (auto& e : edges) { adj[e[0]][e[1]] = e[2]; adj[e[1]][e[0]] = e[2]; }
    priority_queue<pair<int,int>> pq;
    pq.push({maxMoves, 0});
    map<int,int> seen;
    map<pair<int,int>,int> used;
    int ans = 0;
    while (!pq.empty()) {
        auto [moves, u] = pq.top(); pq.pop();
        if (seen.count(u)) continue;
        seen[u] = moves; ans++;
        for (auto [v, cnt] : adj[u]) {
            used[{u, v}] = min(moves, cnt);
            int nxt = moves - cnt - 1;
            if (!seen.count(v) && nxt >= 0) pq.push({nxt, v});
        }
    }
    for (auto& e : edges)
        ans += min(e[2], used[{e[0], e[1]}] + used[{e[1], e[0]}]);
    return ans;
}
Time: O(E log E) Space: O(E)