Facebook Pixel

2467. Most Profitable Path in a Tree

Problem Description

You have an undirected tree with n nodes labeled from 0 to n - 1, rooted at node 0. The tree structure is given by an array edges where edges[i] = [ai, bi] represents an edge between nodes ai and bi.

Each node i has a gate with an associated value in the amount array:

  • If amount[i] is negative, it represents the cost to open the gate
  • If amount[i] is positive or zero, it represents the reward for opening the gate

The game proceeds as follows:

Initial Setup:

  • Alice starts at node 0 (the root)
  • Bob starts at node bob (some other node in the tree)

Movement Rules:

  • Every second, both Alice and Bob move to adjacent nodes simultaneously
  • Alice moves toward a leaf node (a node with only one connection)
  • Bob moves toward node 0 (the root)

Gate Opening Rules:

  • When a player reaches a node, they interact with its gate
  • If the gate hasn't been opened yet:
    • A single player pays the full cost or receives the full reward
    • If both players reach the node simultaneously, they split the cost/reward (each pays/receives amount[i] / 2)
  • If the gate has already been opened, there's no cost or reward

Stopping Conditions:

  • Alice stops when she reaches a leaf node
  • Bob stops when he reaches node 0
  • These events are independent (one can stop while the other continues)

Goal: Find the maximum net income Alice can achieve by choosing the optimal leaf node to travel to. Net income is the sum of all rewards minus all costs along her path.

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: The problem explicitly involves an undirected tree with nodes and edges. A tree is a special type of graph (connected and acyclic).

Is it a tree?

  • Yes: The problem states we have an undirected tree with n nodes connected by n-1 edges, which is the definition of a tree structure.

DFS

  • Yes: We arrive at DFS as the recommended approach.

Conclusion: The flowchart suggests using DFS (Depth-First Search) for this tree problem.

This makes sense because:

  1. We need to explore paths from the root to leaf nodes (Alice's movement)
  2. We need to trace Bob's path from his starting node to the root
  3. Tree traversal naturally fits the DFS pattern where we explore each branch fully before backtracking
  4. The solution requires two DFS traversals:
    • First DFS: Track Bob's path and timing from node bob to node 0
    • Second DFS: Explore all possible paths Alice can take from node 0 to leaf nodes, calculating the maximum profit while considering Bob's timing at each node
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that Bob's path is completely deterministic - he must travel from node bob to node 0 along the unique path that exists in a tree. This means we can precompute exactly when Bob will visit each node on his path.

Think of it this way: Alice has choices (she can pick which leaf to target), but Bob doesn't. Since Bob's movement is fixed, we can simulate his journey first and mark the time he reaches each node along his path.

Once we know Bob's timeline, Alice's problem becomes: "Given that certain nodes will be visited by Bob at specific times, what's the best leaf I can reach to maximize my profit?"

For each node Alice visits, three scenarios can occur:

  1. Alice arrives before Bob - she gets the full amount[i]
  2. Alice and Bob arrive simultaneously - they split amount[i] equally
  3. Alice arrives after Bob - the gate is already open, so she gets nothing

This naturally leads to a two-phase approach:

Phase 1: Run DFS from Bob's starting position to find his path to node 0 and record the time he reaches each node on this path. Nodes not on Bob's path will never be visited by him, so we can mark them with an impossibly large time value.

Phase 2: Run DFS from Alice's starting position (node 0) to explore all possible paths to leaf nodes. At each node, compare Alice's arrival time with Bob's arrival time to determine how much profit/cost Alice incurs. Track the maximum profit among all leaf nodes Alice can reach.

The beauty of this approach is that it separates the deterministic part (Bob's movement) from the optimization part (Alice's choice), making the problem much more manageable.

Learn more about Tree, Depth-First Search, Breadth-First Search and Graph patterns.

Solution Approach

The solution implements the two-phase DFS approach we identified:

Phase 1: Track Bob's Path and Timing

The first DFS function dfs1(i, fa, t) traces Bob's path from his starting node to node 0:

  • i is the current node
  • fa is the parent node (to avoid revisiting)
  • t is the current time

The function recursively explores neighbors until it finds node 0. When found, it returns True and backtracks, recording the time Bob reaches each node along his path in the ts array. The min operation ensures we keep the earliest arrival time if multiple paths exist (though in a tree, the path is unique).

Initially, we set ts[i] = n for all nodes (an impossibly large value), meaning Bob never visits them. After running dfs1, only nodes on Bob's path will have actual time values, with ts[bob] = 0 since Bob starts there.

Phase 2: Find Alice's Optimal Path

The second DFS function dfs2(i, fa, t, v) explores all possible paths Alice can take:

  • i is the current node
  • fa is the parent node
  • t is Alice's current time
  • v is Alice's accumulated profit/cost

At each node, we compare Alice's arrival time t with Bob's arrival time ts[i]:

  • If t == ts[i]: They arrive simultaneously, so Alice gets amount[i] // 2
  • If t < ts[i]: Alice arrives first, so she gets the full amount[i]
  • If t > ts[i]: Bob already opened the gate, so Alice gets nothing (no change to v)

When Alice reaches a leaf node (identified by having only one neighbor, which is the parent), we update the global maximum ans with her accumulated value.

Data Structures Used:

  • g: An adjacency list (defaultdict) to represent the tree structure
  • ts: An array storing Bob's arrival time at each node
  • ans: A global variable tracking the maximum profit Alice can achieve

The algorithm runs in O(n) time since each DFS visits every node once, making it efficient for tree traversal problems.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example to illustrate the solution approach.

Example Input:

  • n = 4 nodes (labeled 0-3)
  • edges = [[0,1], [1,2], [1,3]] (tree structure: 0 -- 1 -- 2, with 3 also connected to 1)
  • amount = [5, -10, 8, 6] (gate values at each node)
  • bob = 2 (Bob starts at node 2)

Tree Visualization:

    0 (5)
    |
    1 (-10)
   / \
  2   3
 (8) (6)

Phase 1: Track Bob's Path (from node 2 to node 0)

Bob must travel: 2 → 1 → 0

Running dfs1(2, -1, 0):

  • Start at node 2 at time 0
  • Move to node 1 at time 1
  • Move to node 0 at time 2
  • Backtrack and record times:
    • ts[2] = 0 (Bob starts here)
    • ts[1] = 1 (Bob reaches at second 1)
    • ts[0] = 2 (Bob reaches at second 2)
    • ts[3] = 4 (never visited, keeps default value)

Phase 2: Find Alice's Optimal Path (from node 0)

Alice has two possible leaf destinations: node 2 or node 3.

Path 1: Alice goes 0 → 1 → 2

  • At node 0 (time 0): Bob arrives at time 2, so Alice arrives first → gets full amount[0] = 5
  • At node 1 (time 1): Bob also arrives at time 1, simultaneous → gets amount[1]/2 = -10/2 = -5
  • At node 2 (time 2): Bob was here at time 0, so gate already open → gets 0
  • Total profit: 5 + (-5) + 0 = 0

Path 2: Alice goes 0 → 1 → 3

  • At node 0 (time 0): Bob arrives at time 2, so Alice arrives first → gets full amount[0] = 5
  • At node 1 (time 1): Bob also arrives at time 1, simultaneous → gets amount[1]/2 = -10/2 = -5
  • At node 3 (time 2): Bob never visits (ts[3] = 4), so Alice arrives first → gets full amount[3] = 6
  • Total profit: 5 + (-5) + 6 = 6

Result: Alice's maximum profit is 6 by choosing to go to leaf node 3.

This example demonstrates how:

  1. Bob's path is fixed and deterministic (2→1→0)
  2. We precompute when Bob reaches each node
  3. Alice evaluates each possible leaf path, accounting for Bob's interference
  4. The optimal choice maximizes Alice's net income

Solution Implementation

1class Solution:
2    def mostProfitablePath(
3        self, edges: List[List[int]], bob: int, amount: List[int]
4    ) -> int:
5        """
6        Find the most profitable path for Alice from node 0 to any leaf node,
7        while Bob travels from his starting node to node 0.
8      
9        Args:
10            edges: List of edges representing the tree
11            bob: Bob's starting node
12            amount: List of values at each node
13      
14        Returns:
15            Maximum profit Alice can obtain
16        """
17      
18        def find_bob_path_to_root(node: int, parent: int, time: int) -> bool:
19            """
20            DFS to find Bob's path from his starting node to node 0 (root).
21            Records the time Bob reaches each node on his path.
22          
23            Args:
24                node: Current node
25                parent: Parent node (to avoid revisiting)
26                time: Current time step
27          
28            Returns:
29                True if current path leads to node 0, False otherwise
30            """
31            # If we reached node 0 (root), update Bob's arrival time
32            if node == 0:
33                bob_arrival_times[node] = min(bob_arrival_times[node], time)
34                return True
35          
36            # Explore all neighbors except parent
37            for neighbor in graph[node]:
38                if neighbor != parent and find_bob_path_to_root(neighbor, node, time + 1):
39                    # If this path leads to root, record Bob's time at this neighbor
40                    bob_arrival_times[neighbor] = min(bob_arrival_times[neighbor], time + 1)
41                    return True
42          
43            return False
44      
45        def calculate_alice_max_profit(node: int, parent: int, time: int, current_profit: int) -> None:
46            """
47            DFS to calculate Alice's maximum profit from root to any leaf.
48            Alice collects values based on when she arrives compared to Bob.
49          
50            Args:
51                node: Current node
52                parent: Parent node (to avoid revisiting)
53                time: Alice's current time step
54                current_profit: Accumulated profit so far
55            """
56            # Calculate profit at current node based on arrival times
57            if time == bob_arrival_times[node]:
58                # Alice and Bob arrive at same time, split the value
59                current_profit += amount[node] // 2
60            elif time < bob_arrival_times[node]:
61                # Alice arrives first, gets full value
62                current_profit += amount[node]
63            # If Bob arrives first, Alice gets nothing (no change to profit)
64          
65            # Update global maximum if this is a leaf node
66            nonlocal max_profit
67            if len(graph[node]) == 1 and graph[node][0] == parent:
68                max_profit = max(max_profit, current_profit)
69                return
70          
71            # Explore all children
72            for neighbor in graph[node]:
73                if neighbor != parent:
74                    calculate_alice_max_profit(neighbor, node, time + 1, current_profit)
75      
76        # Initialize variables
77        n = len(edges) + 1  # Number of nodes
78        graph = defaultdict(list)  # Adjacency list representation
79        bob_arrival_times = [n] * n  # Bob's arrival time at each node (initialized to infinity)
80      
81        # Build the graph from edges
82        for node_a, node_b in edges:
83            graph[node_a].append(node_b)
84            graph[node_b].append(node_a)
85      
86        # Find Bob's path and record his arrival times
87        find_bob_path_to_root(bob, -1, 0)
88        bob_arrival_times[bob] = 0  # Bob starts at time 0 at his starting node
89      
90        # Calculate Alice's maximum profit
91        max_profit = -inf
92        calculate_alice_max_profit(0, -1, 0, 0)
93      
94        return max_profit
95
1class Solution {
2    // Graph adjacency list representation
3    private List<Integer>[] graph;
4    // Array storing the amount of income/cost at each node
5    private int[] amount;
6    // Array storing the time when Bob visits each node
7    private int[] bobVisitTime;
8    // Variable to store the maximum profit
9    private int maxProfit = Integer.MIN_VALUE;
10
11    public int mostProfitablePath(int[][] edges, int bob, int[] amount) {
12        // Calculate number of nodes (edges + 1)
13        int nodeCount = edges.length + 1;
14      
15        // Initialize graph and arrays
16        graph = new List[nodeCount];
17        bobVisitTime = new int[nodeCount];
18        this.amount = amount;
19      
20        // Create adjacency list for each node
21        Arrays.setAll(graph, index -> new ArrayList<>());
22      
23        // Initialize all Bob's visit times to maximum (never visited)
24        Arrays.fill(bobVisitTime, nodeCount);
25      
26        // Build the undirected graph from edges
27        for (var edge : edges) {
28            int nodeA = edge[0];
29            int nodeB = edge[1];
30            graph[nodeA].add(nodeB);
31            graph[nodeB].add(nodeA);
32        }
33      
34        // First DFS: Find Bob's path from his starting position to node 0
35        // and record the time when Bob visits each node on his path
36        findBobPath(bob, -1, 0);
37        bobVisitTime[bob] = 0;  // Bob starts at his position at time 0
38      
39        // Second DFS: Calculate Alice's maximum profit
40        // Alice starts from node 0 at time 0 with profit 0
41        calculateAliceProfit(0, -1, 0, 0);
42      
43        return maxProfit;
44    }
45
46    /**
47     * DFS to find Bob's path from his starting position to node 0
48     * Records the time when Bob visits each node on his path
49     * 
50     * @param currentNode Current node being visited
51     * @param parent Parent node to avoid revisiting
52     * @param time Current time (distance from Bob's starting position)
53     * @return true if current path leads to node 0, false otherwise
54     */
55    private boolean findBobPath(int currentNode, int parent, int time) {
56        // Base case: reached node 0 (Alice's starting position)
57        if (currentNode == 0) {
58            bobVisitTime[currentNode] = Math.min(bobVisitTime[currentNode], time);
59            return true;
60        }
61      
62        // Explore all adjacent nodes
63        for (int neighbor : graph[currentNode]) {
64            // Skip parent node to avoid cycles
65            if (neighbor != parent && findBobPath(neighbor, currentNode, time + 1)) {
66                // If this path leads to node 0, record Bob's visit time
67                bobVisitTime[neighbor] = Math.min(bobVisitTime[neighbor], time + 1);
68                return true;
69            }
70        }
71      
72        return false;
73    }
74
75    /**
76     * DFS to calculate Alice's maximum profit across all possible paths
77     * 
78     * @param currentNode Current node Alice is visiting
79     * @param parent Parent node to avoid revisiting
80     * @param time Current time (distance from Alice's starting position)
81     * @param currentProfit Current accumulated profit
82     */
83    private void calculateAliceProfit(int currentNode, int parent, int time, int currentProfit) {
84        // Calculate profit at current node based on Alice and Bob's arrival times
85        if (time == bobVisitTime[currentNode]) {
86            // Alice and Bob arrive at the same time, split the amount
87            currentProfit += amount[currentNode] >> 1;  // Divide by 2 using bit shift
88        } else if (time < bobVisitTime[currentNode]) {
89            // Alice arrives before Bob, gets full amount
90            currentProfit += amount[currentNode];
91        }
92        // If Alice arrives after Bob, she gets nothing (no addition to profit)
93      
94        // Check if current node is a leaf node (only connected to parent)
95        if (graph[currentNode].size() == 1 && graph[currentNode].get(0) == parent) {
96            // Update maximum profit if current path yields better result
97            maxProfit = Math.max(maxProfit, currentProfit);
98            return;
99        }
100      
101        // Explore all adjacent nodes
102        for (int neighbor : graph[currentNode]) {
103            // Skip parent node to avoid cycles
104            if (neighbor != parent) {
105                calculateAliceProfit(neighbor, currentNode, time + 1, currentProfit);
106            }
107        }
108    }
109}
110
1class Solution {
2public:
3    int mostProfitablePath(vector<vector<int>>& edges, int bob, vector<int>& amount) {
4        // Build adjacency list representation of the tree
5        int n = edges.size() + 1;  // Number of nodes
6        vector<vector<int>> graph(n);
7      
8        // Create bidirectional edges
9        for (auto& edge : edges) {
10            int nodeA = edge[0];
11            int nodeB = edge[1];
12            graph[nodeA].emplace_back(nodeB);
13            graph[nodeB].emplace_back(nodeA);
14        }
15      
16        // Track when Bob visits each node (initialized to max value)
17        vector<int> bobVisitTime(n, n);
18      
19        // DFS to find Bob's path from his starting position to node 0
20        // Records the time Bob visits each node on his path
21        function<bool(int, int, int)> findBobPath = [&](int currentNode, int parent, int time) -> bool {
22            // Found node 0, mark the path
23            if (currentNode == 0) {
24                bobVisitTime[currentNode] = time;
25                return true;
26            }
27          
28            // Explore neighbors
29            for (int neighbor : graph[currentNode]) {
30                if (neighbor != parent && findBobPath(neighbor, currentNode, time + 1)) {
31                    // This node is on Bob's path to 0
32                    bobVisitTime[currentNode] = time;
33                    return true;
34                }
35            }
36            return false;
37        };
38      
39        // Find Bob's path and mark visit times
40        findBobPath(bob, -1, 0);
41      
42        // Calculate maximum profit for Alice
43        int maxProfit = INT_MIN;
44      
45        // DFS for Alice starting from node 0
46        function<void(int, int, int, int)> calculateAliceProfit = [&](int currentNode, int parent, int time, int currentProfit) {
47            // Determine income at current node based on timing with Bob
48            if (time == bobVisitTime[currentNode]) {
49                // Alice and Bob arrive at the same time, split the amount
50                currentProfit += amount[currentNode] >> 1;  // Divide by 2
51            } else if (time < bobVisitTime[currentNode]) {
52                // Alice arrives first, gets full amount
53                currentProfit += amount[currentNode];
54            }
55            // If Alice arrives after Bob, she gets nothing (no update needed)
56          
57            // Check if current node is a leaf (except root)
58            if (graph[currentNode].size() == 1 && graph[currentNode][0] == parent) {
59                // Update maximum profit at leaf nodes
60                maxProfit = max(maxProfit, currentProfit);
61                return;
62            }
63          
64            // Continue DFS to all unvisited neighbors
65            for (int neighbor : graph[currentNode]) {
66                if (neighbor != parent) {
67                    calculateAliceProfit(neighbor, currentNode, time + 1, currentProfit);
68                }
69            }
70        };
71      
72        // Start Alice's journey from node 0
73        calculateAliceProfit(0, -1, 0, 0);
74      
75        return maxProfit;
76    }
77};
78
1function mostProfitablePath(edges: number[][], bob: number, amount: number[]): number {
2    // Build adjacency list representation of the tree
3    const n = edges.length + 1;  // Number of nodes in the tree
4    const graph: number[][] = Array(n).fill(null).map(() => []);
5  
6    // Create bidirectional edges for the tree
7    for (const edge of edges) {
8        const nodeA = edge[0];
9        const nodeB = edge[1];
10        graph[nodeA].push(nodeB);
11        graph[nodeB].push(nodeA);
12    }
13  
14    // Track when Bob visits each node (initialized to maximum value)
15    // If a node is not on Bob's path, it will remain at max value
16    const bobVisitTime: number[] = Array(n).fill(n);
17  
18    // DFS to find Bob's path from his starting position to node 0
19    // Records the time Bob visits each node on his path
20    const findBobPath = (currentNode: number, parent: number, time: number): boolean => {
21        // Found node 0, mark the visit time for this node
22        if (currentNode === 0) {
23            bobVisitTime[currentNode] = time;
24            return true;
25        }
26      
27        // Explore all neighbors to find path to node 0
28        for (const neighbor of graph[currentNode]) {
29            // Skip parent to avoid cycles
30            if (neighbor !== parent && findBobPath(neighbor, currentNode, time + 1)) {
31                // This node is on Bob's path to node 0
32                bobVisitTime[currentNode] = time;
33                return true;
34            }
35        }
36      
37        // This node is not on Bob's path to node 0
38        return false;
39    };
40  
41    // Find Bob's path and mark visit times for nodes on his path
42    findBobPath(bob, -1, 0);
43  
44    // Track the maximum profit Alice can achieve
45    let maxProfit = Number.MIN_SAFE_INTEGER;
46  
47    // DFS for Alice starting from node 0 to calculate maximum profit
48    const calculateAliceProfit = (currentNode: number, parent: number, time: number, currentProfit: number): void => {
49        // Determine income at current node based on timing with Bob
50        if (time === bobVisitTime[currentNode]) {
51            // Alice and Bob arrive at the same time, split the amount equally
52            currentProfit += Math.floor(amount[currentNode] / 2);
53        } else if (time < bobVisitTime[currentNode]) {
54            // Alice arrives before Bob, gets the full amount
55            currentProfit += amount[currentNode];
56        }
57        // If Alice arrives after Bob (time > bobVisitTime[currentNode]), 
58        // she gets nothing as Bob already opened the gate
59      
60        // Check if current node is a leaf node (has only one neighbor which is its parent)
61        // Root node (0) is excluded from this check
62        if (graph[currentNode].length === 1 && graph[currentNode][0] === parent) {
63            // At leaf nodes, update the maximum profit if current profit is higher
64            maxProfit = Math.max(maxProfit, currentProfit);
65            return;
66        }
67      
68        // Continue DFS to all unvisited neighbors (children in the tree)
69        for (const neighbor of graph[currentNode]) {
70            if (neighbor !== parent) {
71                calculateAliceProfit(neighbor, currentNode, time + 1, currentProfit);
72            }
73        }
74    };
75  
76    // Start Alice's journey from node 0 at time 0 with 0 initial profit
77    calculateAliceProfit(0, -1, 0, 0);
78  
79    return maxProfit;
80}
81

Time and Space Complexity

Time Complexity: O(n)

The algorithm consists of two depth-first search (DFS) traversals:

  • dfs1: Traverses from Bob's position to node 0, visiting each node at most once. This takes O(n) time.
  • dfs2: Traverses from node 0 (Alice's starting position) to all leaf nodes, visiting each node exactly once. This also takes O(n) time.

Since both DFS operations run sequentially and each visits nodes at most once, the total time complexity is O(n) + O(n) = O(n).

Space Complexity: O(n)

The space complexity comes from:

  • Graph adjacency list g: Stores all edges, using O(n) space (since it's a tree with n-1 edges, each edge is stored twice).
  • Array ts: Stores timestamps for each node, requiring O(n) space.
  • Recursive call stack: In the worst case (skewed tree), the recursion depth can be O(n).
  • Other variables (ans, parameters) use O(1) space.

Therefore, the total space complexity is O(n).

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrectly Identifying Leaf Nodes

A critical pitfall is misidentifying leaf nodes in the tree. The current code checks if a node is a leaf using:

if len(graph[node]) == 1 and graph[node][0] == parent:

The Problem: This condition fails for node 0 (the root) when it has only one child. Since the root is called with parent = -1, the condition graph[node][0] == parent will be false even if node 0 has degree 1, causing it to not be recognized as a leaf.

Example Scenario:

  • Tree with only 2 nodes: edges = [[0, 1]]
  • Node 0 has degree 1 but won't be identified as a leaf
  • Alice starts at node 0 (which is also a leaf in this case)

Solution:

def calculate_alice_max_profit(node: int, parent: int, time: int, current_profit: int) -> None:
    # Calculate profit at current node
    if time == bob_arrival_times[node]:
        current_profit += amount[node] // 2
    elif time < bob_arrival_times[node]:
        current_profit += amount[node]
  
    # Check if this is a leaf node (degree 1, but not the root with degree 1)
    is_leaf = len(graph[node]) == 1 and node != 0
    # Special case: root is also a leaf if it has degree 0 or 1
    if node == 0 and len(graph[node]) <= 1:
        is_leaf = True
  
    if is_leaf:
        nonlocal max_profit
        max_profit = max(max_profit, current_profit)
        return
  
    # Continue exploring children...

2. Integer Division for Negative Values

When Alice and Bob arrive simultaneously at a node with a negative amount (cost), using integer division // can produce unexpected results.

The Problem:

  • Python's // operator rounds toward negative infinity
  • For example: -5 // 2 = -3 (not -2.5 rounded to -2)
  • This means Alice would pay MORE than half the cost

Example:

  • amount[i] = -5
  • Expected split: Each pays -2.5, rounded to -2
  • Actual with //: Alice pays -3

Solution:

# Instead of:
current_profit += amount[node] // 2

# Use:
current_profit += amount[node] / 2  # Keep as float during calculation

# Or for integer arithmetic with correct rounding:
if amount[node] >= 0:
    current_profit += amount[node] // 2
else:
    # For negative values, use ceiling division to split costs fairly
    current_profit += -(-amount[node] // 2)  # This gives -2 for -5

3. Not Handling Bob's Path Correctly

The current implementation has a subtle bug in tracking Bob's arrival times.

The Problem: The code sets Bob's arrival time after finding his path:

find_bob_path_to_root(bob, -1, 0)
bob_arrival_times[bob] = 0  # Set after the DFS

But inside find_bob_path_to_root, when backtracking, it updates times for nodes on the path including Bob's starting position. This could lead to inconsistent timing.

Solution:

def find_bob_path_to_root(node: int, parent: int, time: int) -> bool:
    # Record Bob's time at this node first
    if node == bob:
        bob_arrival_times[node] = 0
  
    if node == 0:
        bob_arrival_times[node] = min(bob_arrival_times[node], time)
        return True
  
    for neighbor in graph[node]:
        if neighbor != parent and find_bob_path_to_root(neighbor, node, time + 1):
            # Only update if this isn't Bob's starting node
            if node != bob:
                bob_arrival_times[node] = min(bob_arrival_times[node], time)
            return True
  
    return False

# Then call without resetting bob's time afterward:
find_bob_path_to_root(bob, -1, 0)
# Remove: bob_arrival_times[bob] = 0

These pitfalls can cause incorrect results in edge cases, particularly with small trees, negative amounts, or when Bob's starting position has special properties.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What are the two properties the problem needs to have for dynamic programming to be applicable? (Select 2)


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More