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:
- the price needed to open the gate at node
i
, ifamount[i]
is negative, or, - the cash reward obtained on opening the gate at node
i
, otherwise.
The game goes on as follows:
- Initially, Alice is at node
0
and Bob is at nodebob
. - 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 payc / 2
each. Similarly, if the reward at the gate isc
, both of them receivec / 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:
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:
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:
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]
.
Related Topics:
Array, Tree, Depth-First Search, Breadth-First Search, Graph
Similar Questions:
Hints:
- Bob travels along a fixed path (from node “bob” to node 0).
- Calculate Alice’s distance to each node via DFS.
- We can calculate Alice’s score along a path ending at some node easily using Hints 1 and 2.
- DFS from Bob and adjust the amounts along the path from
0
tobob
. - DFS from Alice and calculate the maximum path sum to leaves.
// OJ: https://leetcode.com/problems/most-profitable-path-in-a-tree
// Author: github.com/lzl124631x
// Time: O(N)
// Space: O(N)
class Solution {
public:
int mostProfitablePath(vector<vector<int>>& E, int bob, vector<int>& A) {
int N = A.size(), pathLength = -1;
vector<vector<int>> G(N);
for (auto &e : E) {
int u = e[0], v = e[1];
G[u].push_back(v);
G[v].push_back(u);
}
vector<bool> seen(N);
function<void(int, int)> adjustAmounts = [&](int u, int level) {
if (u == 0) {
pathLength = level + 1;
return;
}
seen[u] = true;
for (int v : G[u]) {
if (seen[v]) continue;
adjustAmounts(v, level + 1);
if (pathLength != -1) break;
}
if (pathLength != -1) {
if (pathLength / 2 == level && pathLength % 2) A[u] /= 2;
else if (pathLength / 2 > level) A[u] = 0;
}
};
adjustAmounts(bob, 0);
seen.assign(N, false);
function<int(int, int)> dfs = [&](int u, int score) {
score += A[u];
int mx = INT_MIN, cnt = 0;
seen[u] = true;
for (int v : G[u]) {
if (seen[v]) continue;
mx = max(mx, dfs(v, score));
++cnt;
}
if (cnt == 0) return score;
return mx;
};
return dfs(0, 0);
}
};
Similar to solution 1, but when DFS from Bob, we just calculate distFromBob
. And then we calculate the optimal income we can get when DFS from Alice.
// OJ: https://leetcode.com/problems/most-profitable-path-in-a-tree
// Author: github.com/lzl124631x
// Time: O(N)
// Space: O(N)
class Solution {
public:
int mostProfitablePath(vector<vector<int>>& E, int bob, vector<int>& A) {
int N = A.size();
vector<vector<int>> G(N);
for (auto &e : E) {
int u = e[0], v = e[1];
G[u].push_back(v);
G[v].push_back(u);
}
vector<int> distFromBob(N, INT_MAX);
function<bool(int, int, int)> calcDistFromBob = [&](int u, int prev, int d) {
distFromBob[u] = d;
if (u == 0) return true;
for (int v : G[u]) {
if (v == prev) continue;
if (calcDistFromBob(v, u, d + 1)) return true;
}
distFromBob[u] = INT_MAX;
return false;
};
calcDistFromBob(bob, -1, 0);
function<int(int, int, int)> dfs = [&](int u, int prev, int d) {
int mx = INT_MIN;
for (int v : G[u]) {
if (v == prev) continue;
mx = max(mx, dfs(v, u, d + 1));
}
int val = d == distFromBob[u] ? A[u] / 2 : (d < distFromBob[u] ? A[u] : 0);
return mx == INT_MIN ? val : val + mx;
};
return dfs(0, -1, 0);
}
};