Minimize the Total Price of the Trips solution and explanation
9 more videos on this problem
Minimize the Total Price of the Trips | Leetcode Contest 341A Code Daily! · 10:21 · 3K views
Minimize the Total Price of the Trips | Harder Follow-up | Weekly Contest 341codingMohan · 44:32 · 1K views
2646. Minimize the Total Price of the Trips | LeetCode Weekly Contest 341Deep Tech · 22:50 · 918 views
Leetcode Weekly contest 341 - Hard - Minimize the Total Price of the TripsPrakhar Agrawal · 18:57 · 857 views
Minimize the Total Price of the Trips - Leetcode 2646 - PythonAlgorithms Casts · 21:59 · 645 views
2646. Minimize the Total Price of the Trips (Leetcode Hard)Programming Live with Larry · 22:21 · 534 views
【每日一题】LeetCode 2646. Minimize the Total Price of the TripsHuifeng Guan · 20:59 · 425 views
Minimize the Total Price of the Trips Leetcode Hard | Leetcode weekly Contest 341 | HindiPawan Kumar Giri · 40:20 · 339 views
Leetcode 2646. Minimize the Total Price of the Trips |Contest 341 | Leetcode weekly contest SolutionOffCampus Phodenge | Aman Chowdhury · 23:01 · 330 views
2646. Minimize the Total Price of the Trips || LEETCODE WEEELY CONTEST 341 || HindiAshish Kumar · 13:54 · 321 views
The problem
There exists an undirected and unrooted tree with n nodes indexed from 0 to n - 1. You are given the integer n and 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.
Each node has an associated price. You are given an integer array price, where price[i] is the price of the ith node.
The price sum of a given path is the sum of the prices of all nodes lying on that path.
Additionally, you are given a 2D integer array trips, where trips[i] = [starti, endi] indicates that you start the ith trip from the node starti and travel to the node endi by any path you like.
Before performing your first trip, you can choose some non-adjacent nodes and halve the prices.
Return the minimum total price sum to perform all the given trips.
Example 1:
Input: n = 4, edges = [[0,1],[1,2],[1,3]], price = [2,2,10,6], trips = [[0,3],[2,1],[2,3]] Output: 23 Explanation: The diagram above denotes the tree after rooting it at node 2. The first part shows the initial tree and the second part shows the tree after choosing nodes 0, 2, and 3, and making their price half. For the 1st trip, we choose path [0,1,3]. The price sum of that path is 1 + 2 + 3 = 6. For the 2nd trip, we choose path [2,1]. The price sum of that path is 2 + 5 = 7. For the 3rd trip, we choose path [2,1,3]. The price sum of that path is 5 + 2 + 3 = 10. The total price sum of all trips is 6 + 7 + 10 = 23. It can be proven, that 23 is the minimum answer that we can achieve.
Example 2:
Input: n = 2, edges = [[0,1]], price = [2,2], trips = [[0,0]] Output: 1 Explanation: The diagram above denotes the tree after rooting it at node 0. The first part shows the initial tree and the second part shows the tree after choosing node 0, and making its price half. For the 1st trip, we choose path [0]. The price sum of that path is 1. The total price sum of all trips is 1. It can be proven, that 1 is the minimum answer that we can achieve.
Constraints:
1 <= n <= 50edges.length == n - 10 <= ai, bi <= n - 1edgesrepresents a valid tree.price.length == nprice[i]is an even integer.1 <= price[i] <= 10001 <= trips.length <= 1000 <= starti, endi <= n - 1
Approach overview
Problem Overview: You are given a tree with n nodes where each node has a price. Multiple trips occur between pairs of nodes, and the cost of a trip is the sum of prices along its path. Some nodes can have their price halved, but no two adjacent nodes can both be halved. The goal is to choose which nodes to discount so the total price across all trips is minimized.
Approach 1: DFS Traversal to Count Node Usage (Time: O(t * n), Space: O(n))
The first step is determining how many times each node contributes to the total cost. Build the tree using an adjacency list and run a DFS for every trip to find the path from source to destination. While backtracking, increment a frequency counter for each node on that path. After processing all trips, you know exactly how often each node's price is used in the total sum. The effective weight of a node becomes price[i] * freq[i]. This step relies on standard Depth-First Search traversal on a tree structure.
Approach 2: Dynamic Programming on Trees (Time: O(n), Space: O(n))
Once node frequencies are known, the problem becomes a tree version of the "House Robber" constraint: you cannot halve two adjacent nodes. Run another DFS with two states per node. dp0 represents the minimum cost if the current node is not discounted. dp1 represents the cost if the node is discounted (its contribution becomes (price[i] * freq[i]) / 2). If a node is discounted, none of its children can be discounted. During traversal, aggregate child costs accordingly: dp0 += min(child.dp0, child.dp1) and dp1 += child.dp0. This is classic Dynamic Programming on a graph that happens to be a tree. The final answer is min(root.dp0, root.dp1).
Recommended for interviews: Interviewers expect the tree DP solution. The DFS path counting step demonstrates you understand how to accumulate trip usage, while the dynamic programming phase shows mastery of tree state transitions. The optimal reasoning combines graph traversal with a two-state DP similar to House Robber on trees.
Approach 1: Depth-First Search (DFS) Traversal
Depth-First Search (DFS) is an effective method for traversing trees and graphs, which can help calculate the price sums over paths efficiently. In this method, the tree is traversed using DFS from each start node to the end node of each trip. The path is traversed by performing a DFS from the root node and accumulating the price at each node until reaching the end node of a trip.
def dfs_minimize_price(n, edges, price, trips):
from collections import defaultdict
# Build graph
graph = defaultdict(list)
for u, v in edges:
graph[u].append(v)
graph[v].append(u)
def dfs(start, end, visited):
if start == end:
return [start]
visited.add(start)
for neighbor in graph[start]:
if neighbor not in visited:
path = dfs(neighbor, end, visited)
if path:
return [start] + path
visited.remove(start)
return []
minimal_price_sum = 0
for start, end in trips:
path = dfs(start, end, set())
minimal_price_sum += sum(price[node] for node in path) // 2
return minimal_price_sum
# Example usage:
print(dfs_minimize_price(4, [[0,1],[1,2],[1,3]], [2,2,10,6], [[0,3],[2,1],[2,3]])) # Output: 23#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
using namespace std;
void dfs(int node, int end, unordered_map<int, vector<int>>& graph, vector<bool>& visited, vector<int>& path, vector<int>& current_path, unordered_set<int>& non_adjacent, const vector<int>& price) {
visited[node] = true;
current_path.push_back(node);
if (node == end) {
for (const int& p : current_path) {
if (non_adjacent.find(p) == non_adjacent.end()) {
path.push_back(p);
non_adjacent.insert(p);
break;
}
}
visited[node] = false;
current_path.pop_back();
return;
}
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfs(neighbor, end, graph, visited, path, current_path, non_adjacent, price);
}
}
visited[node] = false;
current_path.pop_back();
}
int minimizeDFSPriceSum(int n, vector<vector<int>>& edges, vector<int>& price, vector<vector<int>>& trips) {
unordered_map<int, vector<int>> graph;
for (const auto& edge : edges) {
graph[edge[0]].push_back(edge[1]);
graph[edge[1]].push_back(edge[0]);
}
int minimal_price_sum = 0;
for (const auto& trip : trips) {
vector<bool> visited(n, false);
vector<int> path;
vector<int> current_path;
unordered_set<int> non_adjacent;
dfs(trip[0], trip[1], graph, visited, path, current_path, non_adjacent, price);
for (int node : path) {
minimal_price_sum += price[node] / 2;
}
}
return minimal_price_sum;
}
int main() {
vector<vector<int>> edges = {{0, 1}, {1, 2}, {1, 3}};
vector<int> price = {2, 2, 10, 6};
vector<vector<int>> trips = {{0, 3}, {2, 1}, {2, 3}};
cout << minimizeDFSPriceSum(4, edges, price, trips) << endl;
return 0;
}The solution first constructs a graph representation of the tree using adjacency lists. A DFS function is defined to find paths from the start to end nodes. For each specified trip in the input, DFS is run to find the path, from which price sums are calculated and divided by two (simulating halving prices). The key detail is using a visited set to prevent revisiting nodes, ensuring non-adjacent nodes have their prices halved where possible.
Time Complexity: O(n * t), where n is the number of nodes and t is the number of trips, because DFS will run once for every trip.
Space Complexity: O(n), due to the recursion stack and the graph representation.
Approach 2: Dynamic Programming on Trees
Dynamic Programming on Trees is a strategy where you traverse the tree with dynamic programming techniques in mind, to keep track of possible price reductions on paths. This approach benefits from storing results for subproblems that can be reused later.
import java.util.*;
public class PriceMinimizer {
private static int dfs(int node, int parent, Map<Integer, List<Integer>> graph, int[] dpFull, int[] dpHalf, int[] price) {
dpFull[node] = price[node];
dpHalf[node] = price[node] / 2;
for (int neighbor : graph.get(node)) {
if (neighbor == parent) continue;
dfs(neighbor, node, graph, dpFull, dpHalf, price);
dpFull[node] += dpFull[neighbor];
dpHalf[node] += dpHalf[neighbor];
}
return Math.min(dpFull[node], dpHalf[node]);
}
public static int minimizePriceSum(int n, int[][] edges, int[] price, int[][] trips) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < n; i++) graph.put(i, new ArrayList<>());
for (int[] edge : edges) {
graph.get(edge[0]).add(edge[1]);
graph.get(edge[1]).add(edge[0]);
}
int[] dpFull = new int[n]; // full price
int[] dpHalf = new int[n]; // half price
int minPrice = Integer.MAX_VALUE;
for (int[] trip : trips) {
minPrice = Math.min(minPrice, dfs(trip[1], -1, graph, dpFull, dpHalf, price));
}
return minPrice;
}
public static void main(String[] args) {
int[][] edges = {{0,1},{1,2},{1,3}};
int[] price = {2,2,10,6};
int[][] trips = {{0,3},{2,1},{2,3}};
System.out.println(minimizePriceSum(4, edges, price, trips)); // Output: 23
}
}function minimizePriceSum(n, edges, price, trips) {
const graph = Array.from({ length: n }, () => []);
for (const [u, v] of edges) {
graph[u].push(v);
graph[v].push(u);
}
function dfs(node, parent, dpFull, dpHalf) {
dpFull[node] = price[node];
dpHalf[node] = price[node] / 2;
for (const neighbor of graph[node]) {
if (neighbor === parent) continue;
dfs(neighbor, node, dpFull, dpHalf);
dpFull[node] += dpFull[neighbor];
dpHalf[node] += dpHalf[neighbor];
}
}
let minPrice = Infinity;
for (const [start, end] of trips) {
const dpFull = Array(n).fill(0);
const dpHalf = Array(n).fill(0);
dfs(end, -1, dpFull, dpHalf);
minPrice = Math.min(minPrice, dpFull[end], dpHalf[end]);
}
return minPrice;
}
// Example usage:
console.log(minimizePriceSum(4, [[0,1],[1,2],[1,3]], [2,2,10,6], [[0,3],[2,1],[2,3]])); // Output: 23The solution employs dynamic programming to compute the minimum price for each node both with full and half prices. The DFS function is used to populate the dpFull and dpHalf arrays as it traverses the tree. The result is built by considering already computed results of children nodes, thus efficiently halving the price at non-adjacent nodes for minimizing the price sums required on the trips.
Time Complexity: O(n), as each node and edge is visited once in the DFS traversal.
Space Complexity: O(n), for the DP arrays and graph structure.
Approach 3: Enumeration
We can enumerate each element div in divisors, and calculate how many elements in nums can be divided by div, denoted as cnt.
- If
cntis greater than the current maximum divisibility scoremx, then updatemx = cnt, and updateans = div. - If
cntequalsmxanddivis less thanans, then updateans = div.
Finally, return ans.
The time complexity is O(m times n), where m and n are the lengths of nums and divisors respectively. The space complexity is O(1).
function minimumTotalPrice(
n: number,
edges: number[][],
price: number[],
trips: number[][],
): number {
const g: number[][] = Array.from({ length: n }, () => []);
for (const [a, b] of edges) {
g[a].push(b);
g[b].push(a);
}
const cnt: number[] = new Array(n).fill(0);
const dfs = (i: number, fa: number, k: number): boolean => {
++cnt[i];
if (i === k) {
return true;
}
let ok = false;
for (const j of g[i]) {
if (j !== fa) {
ok = dfs(j, i, k);
if (ok) {
break;
}
}
}
if (!ok) {
--cnt[i];
}
return ok;
};
for (const [start, end] of trips) {
dfs(start, -1, end);
}
const dfs2 = (i: number, fa: number): number[] => {
let a: number = price[i] * cnt[i];
let b: number = a >> 1;
for (const j of g[i]) {
if (j !== fa) {
const [x, y] = dfs2(j, i);
a += Math.min(x, y);
b += x;
}
}
return [a, b];
};
const [a, b] = dfs2(0, -1);
return Math.min(a, b);
}func minimumTotalPrice(n int, edges [][]int, price []int, trips [][]int) int {
g := make([][]int, n)
for _, e := range edges {
a, b := e[0], e[1]
g[a] = append(g[a], b)
g[b] = append(g[b], a)
}
cnt := make([]int, n)
var dfs func(int, int, int) bool
dfs = func(i, fa, k int) bool {
cnt[i]++
if i == k {
return true
}
ok := false
for _, j := range g[i] {
if j != fa {
ok = dfs(j, i, k)
if ok {
break
}
}
}
if !ok {
cnt[i]--
}
return ok
}
for _, t := range trips {
start, end := t[0], t[1]
dfs(start, -1, end)
}
var dfs2 func(int, int) (int, int)
dfs2 = func(i, fa int) (int, int) {
a := price[i] * cnt[i]
b := a >> 1
for _, j := range g[i] {
if j != fa {
x, y := dfs2(j, i)
a += min(x, y)
b += x
}
}
return a, b
}
a, b := dfs2(0, -1)
return min(a, b)
}Complexity comparison
| Approach | Complexity |
|---|---|
| Depth-First Search (DFS) Traversal | Time Complexity: O(n * t), where n is the number of nodes and t is the number of trips, because DFS will run once for every trip. |
| Dynamic Programming on Trees | Time Complexity: O(n), as each node and edge is visited once in the DFS traversal. |
| Enumeration | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| DFS Traversal to Count Trip Paths | O(t * n) | O(n) | When constraints are small and you need to compute how often each node appears in trip paths |
| Dynamic Programming on Trees | O(n) | O(n) | General optimal solution for minimizing cost with adjacency constraints on tree nodes |
Frequently asked questions
Is Minimize the Total Price of the Trips easy or hard?
Minimize the Total Price of the Trips is classified as a Hard problem on LeetCode. The difficulty comes from combining two ideas: counting node usage across multiple paths in a tree and applying a two-state dynamic programming strategy similar to House Robber on trees.
Minimize the Total Price of the Trips Python/Java solution
Typical implementations use DFS to find each trip path and count node frequencies, followed by a tree DP. Python solutions rely on recursion and adjacency lists, while Java versions maintain two DP states per node inside a recursive traversal. Both implementations run in O(t * n) preprocessing and O(n) DP time.
How to solve Minimize the Total Price of the Trips in O(n)?
The optimization step itself runs in O(n) using tree dynamic programming. After computing node visit frequencies, perform a DFS where each node maintains two states: cost without discount and cost with discount. Children cannot be discounted if the parent is discounted, producing a classic two-state tree DP.
What is the best approach for Minimize the Total Price of the Trips?
The optimal approach combines DFS path counting with dynamic programming on trees. First count how many times each node appears in all trip paths using DFS. Then run a tree DP with two states per node (discounted or not discounted) while enforcing that adjacent nodes cannot both be discounted. The DP runs in O(n) after preprocessing.
Is Minimize the Total Price of the Trips asked at Google/Amazon/Meta?
Tree dynamic programming and path aggregation problems like this frequently appear in interviews at companies such as Google, Amazon, and Meta. Variants of the House Robber on trees or graph traversal combined with DP are common interview patterns.
What data structure is used in Minimize the Total Price of the Trips?
The main data structure is an adjacency list representing the tree. Depth-first search traverses the graph to compute trip paths and perform the DP transitions. Arrays store node prices, frequency counts, and DP states for each node.
What is the time complexity of Minimize the Total Price of the Trips?
The overall time complexity is O(t * n + n), where t is the number of trips and n is the number of nodes. DFS is executed once per trip to determine the nodes on each path, and a second DFS performs the dynamic programming over the tree. Space complexity is O(n) for adjacency lists, recursion stack, and DP states.
