2564 Most Profitable Path In A Tree
2564 Most Profitable Path In A Tree
Most Profitable Path in a Tree 
There is an undirected tree with n nodes labeled from 0 to n - 1, rooted at node 0. You are given a 2D integer array edges of length n - 1 where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree.
At every node i, there is a gate. You are also given an array of even integers amount, where amount[i] represents:
1
2
the price needed to open the gate at node i, if amount[i] is negative, or,
the cash reward obtained on opening the gate at node i, otherwise.
The game goes on as follows:
1
2
3
4
5
6
7
8
Initially, Alice is at node 0 and Bob is at node bob.
At every second, Alice and Bob **each** move to an adjacent node. Alice moves towards some **leaf node**, while Bob moves towards node 0.
For **every** node along their path, Alice and Bob either spend money to open the gate at that node, or accept the reward. Note that:
If the gate is **already open**, no price will be required, nor will there be any cash reward.
If Alice and Bob reach the node **simultaneously**, they share the price/reward for opening the gate there. In other words, if the price to open the gate is c, then both Alice and Bob pay c / 2 each. Similarly, if the reward at the gate is c, both of them receive c / 2 each.
If Alice reaches a leaf node, she stops moving. Similarly, if Bob reaches node 0, he stops moving. Note that these events are **independent** of each other.
Return* the maximum net income Alice can have if she travels towards the optimal leaf node.*
Example 1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
**Input:** edges = [[0,1],[1,2],[1,3],[3,4]], bob = 3, amount = [-2,4,2,-4,6]
**Output:** 6
**Explanation:**
The above diagram represents the given tree. The game goes as follows:
- Alice is initially on node 0, Bob on node 3. They open the gates of their respective nodes.
Alice's net income is now -2.
- Both Alice and Bob move to node 1.
Since they reach here simultaneously, they open the gate together and share the reward.
Alice's net income becomes -2 + (4 / 2) = 0.
- Alice moves on to node 3. Since Bob already opened its gate, Alice's income remains unchanged.
Bob moves on to node 0, and stops moving.
- Alice moves on to node 4 and opens the gate there. Her net income becomes 0 + 6 = 6.
Now, neither Alice nor Bob can make any further moves, and the game ends.
It is not possible for Alice to get a higher net income.
Example 2:
1
2
3
4
5
6
7
**Input:** edges = [[0,1]], bob = 1, amount = [-7280,2350]
**Output:** -7280
**Explanation:**
Alice follows the path 0->1 whereas Bob follows the path 1->0.
Thus, Alice opens the gate at node 0 only. Hence, her net income is -7280.
Constraints:
1
2
3
4
5
6
7
8
9
2 <= n <= 105
edges.length == n - 1
edges[i].length == 2
0 <= ai, bi < n
ai != bi
edges represents a valid tree.
1 <= bob < n
amount.length == n
amount[i] is an **even** integer in the range [-104, 104].
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Solution:
def __init__(self):
self.bob_path = {}
self.visited = []
self.tree = []
def mostProfitablePath(self, edges, bob, amount):
n = len(amount)
max_income = float("-inf")
self.tree = [[] for _ in range(n)]
self.bob_path = {}
self.visited = [False] * n
node_queue = deque([(0, 0, 0)])
# Form tree with edges
for edge in edges:
self.tree[edge[0]].append(edge[1])
self.tree[edge[1]].append(edge[0])
# Find the path taken by Bob to reach node 0 and the times it takes to get there
self.find_bob_path(bob, 0)
# Breadth First Search
self.visited = [False] * n
while node_queue:
source_node, time, income = node_queue.popleft()
# Alice reaches the node first
if (
source_node not in self.bob_path
or time < self.bob_path[source_node]
):
income += amount[source_node]
# Alice and Bob reach the node at the same time
elif time == self.bob_path[source_node]:
income += amount[source_node] // 2
# Update max value if current node is a new leaf
if len(self.tree[source_node]) == 1 and source_node != 0:
max_income = max(max_income, income)
# Explore adjacent unvisited vertices
for adjacent_node in self.tree[source_node]:
if not self.visited[adjacent_node]:
node_queue.append((adjacent_node, time + 1, income))
# Mark and remove current node
self.visited[source_node] = True
return max_income
# Depth First Search
def find_bob_path(self, source_node, time):
# Mark and set time node is reached
self.bob_path[source_node] = time
self.visited[source_node] = True
# Destination for Bob is found
if source_node == 0:
return True
# Traverse through unvisited nodes
for adjacent_node in self.tree[source_node]:
if not self.visited[adjacent_node]:
if self.find_bob_path(adjacent_node, time + 1):
return True
# If node 0 isn't reached, remove current node from path
self.bob_path.pop(source_node, None)
return False
This post is licensed under CC BY 4.0 by the author.

