Π‘ΡΡΠ»ΠΊΠ° Π½Π° Π·Π°Π΄Π°ΡΡ β 2467. Most Profitable Path in a Tree.
π ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π·Π°Π΄Π°ΡΠΈ
ΠΠ°Π½ΠΎ Π½Π΅ΠΎΡΠΈΠ΅Π½ΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΊΠΎΡΠ½Π΅Π²ΠΎΠ΅ Π΄Π΅ΡΠ΅Π²ΠΎ Ρ n
ΡΠ·Π»Π°ΠΌΠΈ (Π½ΡΠΌΠ΅ΡΠΎΠ²Π°Π½Π½ΡΠΌΠΈ ΠΎΡ 0
Π΄ΠΎ n-1
).
- Π£ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠ·Π»Π° Π΅ΡΡΡ Π²ΡΠ°ΡΠ°, ΠΎΡΠΊΡΡΡΠΈΠ΅ ΠΊΠΎΡΠΎΡΡΡ
ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠΈΠ½Π΅ΡΡΠΈ ΠΏΡΠΈΠ±ΡΠ»Ρ ΠΈΠ»ΠΈ ΠΏΠΎΡΡΠ΅Π±ΠΎΠ²Π°ΡΡ Π·Π°ΡΡΠ°Ρ (
amount[i]
).
- ΠΠ»ΠΈΡΠ° Π½Π°ΡΠΈΠ½Π°Π΅Ρ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΎΡ ΠΊΠΎΡΠ½Ρ (
0
) ΠΊ ΠΊΠ°ΠΊΠΎΠΌΡ-Π»ΠΈΠ±ΠΎ Π»ΠΈΡΡΡ, Π²ΡΠ±ΠΈΡΠ°Ρ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎ Π²ΡΠ³ΠΎΠ΄Π½ΡΠΉ ΠΏΡΡΡ.
- ΠΠΎΠ± Π½Π°ΡΠΈΠ½Π°Π΅Ρ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΡΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Π²Π΅ΡΡΠΈΠ½Ρ
bob
ΠΈ Π΄Π²ΠΈΠΆΠ΅ΡΡΡ ΠΊ ΠΊΠΎΡΠ½Ρ (0
).
- ΠΡΠ»ΠΈ ΠΠ»ΠΈΡΠ° ΠΈ ΠΠΎΠ± ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ ΠΏΠΎΡΠ΅ΡΠ°ΡΡ ΡΠ·Π΅Π», ΠΎΠ½ΠΈ Π΄Π΅Π»ΡΡ
ΡΡΠΎΠΈΠΌΠΎΡΡΡ/ΠΏΡΠΈΠ±ΡΠ»Ρ
ΠΏΠΎΠΏΠΎΠ»Π°ΠΌ.
ΠΡΠΆΠ½ΠΎ Π½Π°ΠΉΡΠΈ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ ΡΠΈΡΡΡΠΉ Π΄ΠΎΡ
ΠΎΠ΄ ΠΠ»ΠΈΡΡ ΠΏΡΠΈ ΠΎΠΏΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠΌ Π²ΡΠ±ΠΎΡΠ΅ ΠΏΡΡΠΈ.
π ΠΠ΄Π΅Ρ
ΠΠΌΠ΅ΡΡΠΎ ΡΠ°Π·Π΄Π΅Π»ΡΠ½ΠΎΠ³ΠΎ Π·Π°ΠΏΡΡΠΊΠ° BFS
Π΄Π»Ρ ΠΏΠΎΠΈΡΠΊΠ° ΠΏΡΡΠΈ ΠΠΎΠ±Π° ΠΈ ΠΏΠΎΡΠ»Π΅Π΄ΡΡΡΠ΅Π³ΠΎ ΠΏΡΠΎΡ
ΠΎΠ΄Π° Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎ ΡΠ·Π»Π°ΠΌ Π΄Π΅ΡΠ΅Π²Π°, ΠΌΡ ΡΠ΅ΡΠΈΠΌ Π·Π°Π΄Π°ΡΡ ΠΎΠ΄Π½ΠΈΠΌ ΡΠ΅ΠΊΡΡΡΠΈΠ²Π½ΡΠΌ DFS-ΠΏΡΠΎΡ
ΠΎΠ΄ΠΎΠΌ.
ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠ·Π»Π° Π±ΡΠ΄Π΅ΠΌ Π²ΡΡΠΈΡΠ»ΡΡΡ:
alice_profit[node]
β ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ Π΄ΠΎΡ
ΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΠΎΠΆΠ΅Ρ ΡΠΎΠ±ΡΠ°ΡΡ ΠΠ»ΠΈΡΠ° ΠΈΠ· ΠΏΠΎΠ΄Π΄Π΅ΡΠ΅Π²Π°.
bob_distance[node]
β ΡΠ°ΡΡΡΠΎΡΠ½ΠΈΠ΅ Π½Π° ΠΏΡΡΠΈ ΠΠΎΠ±Π° Π΄ΠΎ ΡΡΠΎΠΉ Π²Π΅ΡΡΠΈΠ½Ρ.
- ΠΡΠ»ΠΈ ΠΠΎΠ± ΡΠ°Π½ΡΡΠ΅ Π΄ΠΎΠ±Π΅ΡΡΡΡΡ Π΄ΠΎ ΡΠ·Π»Π° β ΠΠ»ΠΈΡΠ° Π½ΠΈΡΠ΅Π³ΠΎ Π½Π΅ ΠΏΠΎΠ»ΡΡΠΈΡ.
- ΠΡΠ»ΠΈ ΠΠ»ΠΈΡΠ° ΠΈ ΠΠΎΠ± ΠΏΡΠΈΡ
ΠΎΠ΄ΡΡ ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ β Π΄Π΅Π»ΠΈΠΌ ΠΏΡΠΈΠ±ΡΠ»Ρ ΠΏΠΎΠΏΠΎΠ»Π°ΠΌ.
- ΠΡΠ»ΠΈ ΠΠ»ΠΈΡΠ° ΠΏΡΠΈΡ
ΠΎΠ΄ΠΈΡ ΡΠ°Π½ΡΡΠ΅ β ΠΎΠ½Π° ΠΏΠΎΠ»ΡΡΠ°Π΅Ρ Π²ΡΡ ΡΡΠΌΠΌΡ.
π‘ Π ΠΈΡΠΎΠ³Π΅ ΠΎΠ΄Π½ΠΈΠΌ DFS Π²ΡΡΠΈΡΠ»ΠΈΠΌ ΠΎΠΏΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ ΠΏΡΡΡ ΠΠ»ΠΈΡΡ ΠΈ ΡΡΡΡΠΌ Π²Π»ΠΈΡΠ½ΠΈΠ΅ ΠΠΎΠ±Π°. π
π ΠΠΎΠ΄ΡΠΎΠ±Π½ΠΎΡΡΠΈ ΠΏΠΎΠ΄Ρ
ΠΎΠ΄Π°
- Π‘ΡΡΠΎΠΈΠΌ Π΄Π΅ΡΠ΅Π²ΠΎ Π² Π²ΠΈΠ΄Π΅ ΡΠΏΠΈΡΠΊΠ° ΡΠΌΠ΅ΠΆΠ½ΠΎΡΡΠΈ (
Vec<Vec<usize>>
).
- ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΡΠ΅ΠΊΡΡΡΠΈΠ²Π½ΡΠΉ DFS:
- ΠΡΠ»ΠΈ ΡΠ·Π΅Π» β Π»ΠΈΡΡ, Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΠΌ
amount[node]
(ΠΈΠ»ΠΈ 0
, Π΅ΡΠ»ΠΈ ΡΠ°ΠΌ ΠΠΎΠ±).
- Π Π΅ΠΊΡΡΡΠΈΠ²Π½ΠΎ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΠΌΡΡ ΠΈΠ· ΡΠΎΡΠ΅Π΄Π΅ΠΉ (ΠΈΡΠΊΠ»ΡΡΠ°Ρ ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ).
- ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠ°ΡΡΡΠΎΡΠ½ΠΈΠ΅ Π½Π° ΠΏΡΡΠΈ ΠΎΡ ΠΠΎΠ±Π°.
- ΠΡΠ±ΠΈΡΠ°Π΅ΠΌ Π½Π°ΠΈΠ»ΡΡΡΠΈΠΉ Π΄ΠΎΡ
ΠΎΠ΄ ΠΠ»ΠΈΡΡ.
- ΠΠΎΡΡΠ΅ΠΊΡΠΈΡΡΠ΅ΠΌ Π΄ΠΎΡ
ΠΎΠ΄ Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΡΠ°ΡΡΡΠΈΡΠ°Π½Π½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ½ΠΈ ΠΠΎΠ±Π°.
β³ ΠΡΠΈΠΌΠΏΡΠΎΡΠΈΠΊΠ°
-
π ΠΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ:
O(N)
- ΠΠ°ΠΆΠ΄Π°Ρ Π²Π΅ΡΡΠΈΠ½Π° ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΡΡΡ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·
- ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠ·Π»Π° β
O(1)
-
π¦ ΠΠ°ΡΡΠ°ΡΡ ΠΏΠ°ΠΌΡΡΠΈ:
O(N)
- Π₯ΡΠ°Π½ΠΈΠΌ ΡΠΏΠΈΡΠΎΠΊ ΡΠΌΠ΅ΠΆΠ½ΠΎΡΡΠΈ (
O(N)
).
- ΠΠ»ΡΠ±ΠΈΠ½Π° ΡΠ΅ΠΊΡΡΡΠΈΠΈ β
O(N)
Π² Ρ
ΡΠ΄ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°Π΅ (Π»ΠΈΠ½Π΅ΠΉΠ½ΠΎΠ΅ Π΄Π΅ΡΠ΅Π²ΠΎ).
π» ΠΡΡ
ΠΎΠ΄Π½ΡΠΉ ΠΊΠΎΠ΄
use std::cmp::Ordering::{Less, Equal, Greater};
struct ProblemContext<'a> {
bob: usize,
amount: &'a [i32],
tree: &'a [Vec<usize>],
}
impl Solution {
pub fn most_profitable_path(edges: Vec<Vec<i32>>, bob: i32, amount: Vec<i32>) -> i32 {
let n = amount.len();
let mut tree = vec![vec![]; n];
// Construct adjacency list
for edge in &edges {
let (u, v) = (edge[0] as usize, edge[1] as usize);
tree[u].push(v);
tree[v].push(u);
}
let ctx = ProblemContext {
bob: bob as usize,
amount: &amount,
tree: &tree,
};
// Start DFS from the root (0), parent set as usize::MAX (invalid parent)
let (alice_profit, _) = Self::dp_rec(0, usize::MAX, 0, &ctx);
alice_profit
}
// Recursive DFS to compute Alice's max profit and Bob's distance from `node`
fn dp_rec(node: usize, parent: usize, current_depth: usize, ctx: &ProblemContext) -> (i32, usize) {
let bob_init_depth = if node == ctx.bob { 0 } else { ctx.tree.len() };
// If `node` is a leaf (not the root), handle Alice's profit correctly
if ctx.tree[node].len() == 1 && current_depth != 0 {
let alice_profit = if node == ctx.bob { 0 } else { ctx.amount[node] };
return (alice_profit, bob_init_depth);
}
// Explore child nodes recursively and find:
// - Maximum profit Alice can collect (`alice_profit`)
// - Minimum distance Bob needs to reach this node (`bob_distance`)
let (alice_profit, bob_distance) = ctx.tree[node]
.iter()
.filter(|&&neighbor| neighbor != parent) // Avoid backtracking to parent
.map(|&neighbor| Self::dp_rec(neighbor, node, current_depth + 1, ctx))
.fold((i32::MIN, bob_init_depth), |(a_profit, b_dist), (a, b)| {
(a_profit.max(a), b_dist.min(b + 1))
});
// Adjust Alice's profit based on when Bob arrives at this node
let adjusted_profit = match current_depth.cmp(&bob_distance) {
Less => alice_profit + ctx.amount[node], // Alice arrives first β full amount
Equal => alice_profit + ctx.amount[node] / 2, // Alice & Bob arrive together β split amount
Greater => alice_profit, // Bob arrives first β Alice gets nothing
};
(adjusted_profit, bob_distance)
}
}
Tags: #rust #algorithms #tree #dp #dfs