Maximum Weighted K-Edge Path
MedPrompt
You are given an integer n and a Directed Acyclic Graph (DAG) with n nodes labeled from 0 to n - 1. This is represented by a 2D array edges, where edges[i] = [ui, vi, wi] indicates a directed edge from node ui to vi with weight wi.
You are also given two integers, k and t.
Your task is to determine the maximum possible sum of edge weights for any path in the graph such that:
- The path contains exactly
kedges. - The total sum of edge weights in the path is strictly less than
t.
Return the maximum possible sum of weights for such a path. If no such path exists, return -1.
Example 1:
Input: n = 3, edges = [[0,1,1],[1,2,2]], k = 2, t = 4
Output: 3
Explanation:

- The only path with
k = 2edges is0 -> 1 -> 2with weight1 + 2 = 3 < t. - Thus, the maximum possible sum of weights less than
tis 3.
Example 2:
Input: n = 3, edges = [[0,1,2],[0,2,3]], k = 1, t = 3
Output: 2
Explanation:

- There are two paths with
k = 1edge:0 -> 1with weight2 < t.0 -> 2with weight3 = t, which is not strictly less thant.
- Thus, the maximum possible sum of weights less than
tis 2.
Example 3:
Input: n = 3, edges = [[0,1,6],[1,2,8]], k = 1, t = 6
Output: -1
Explanation:

- There are two paths with k = 1 edge:
0 -> 1with weight6 = t, which is not strictly less thant.1 -> 2with weight8 > t, which is not strictly less thant.
- Since there is no path with sum of weights strictly less than
t, the answer is -1.
Constraints:
1 <= n <= 3000 <= edges.length <= 300edges[i] = [ui, vi, wi]0 <= ui, vi < nui != vi1 <= wi <= 100 <= k <= 3001 <= t <= 600- The input graph is guaranteed to be a DAG.
- There are no duplicate edges.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves exploring every possible path of length k in the graph. We can use a Depth First Search (DFS) traversal starting from each node. The recursion keeps track of the current path's length and total weight.
Algorithm
- Initialize a global variable
max_valid_weight = -1. - Build an adjacency list representation of the graph from the
edgesarray. - Define a recursive function
dfs(node, k, weight). - In
dfs, ifk == 0, check ifweight < tand updatemax_valid_weight = max(max_valid_weight, weight). Then return. - For each neighbor
vofnodewith edge weightw, calldfs(v, k - 1, weight + w). - Iterate through each node
ifrom 0 ton-1and start the search by callingdfs(i, k, 0). - Return
max_valid_weight.
Walkthrough
We can model this problem as finding all paths of a specific length. A recursive DFS function, say dfs(u, edges_left, current_weight), can be designed to explore these paths.
- State: The function takes the current node
u, the number of edges left to traverseedges_left, and the accumulated weightcurrent_weight. - Base Case: When
edges_leftbecomes 0, it means we have formed a path with exactlykedges. We then check if itscurrent_weightis strictly less thant. If it is, we compare it with a global maximum weight and update if necessary. - Recursive Step: For the current node
u, the function iterates through all its neighborsv. For each edge(u, v)with weightw, it makes a recursive calldfs(v, edges_left - 1, current_weight + w). - Initialization: To ensure all possible paths are considered, we must initiate the DFS from every node in the graph, i.e., call
dfs(i, k, 0)for allifrom 0 ton-1.
This method is exhaustive but computationally very expensive.
Complexity
Time
O(n * d^k), where `d` is the average out-degree of nodes. The number of paths of length `k` can be exponential, making this approach infeasible for the given constraints.
Space
O(k) for the recursion stack depth.
Trade-offs
Pros
Conceptually simple and easy to understand.
Cons
Extremely inefficient and will result in a 'Time Limit Exceeded' error for the given constraints.
A more efficient solution uses dynamic programming. This problem exhibits optimal substructure and overlapping subproblems, as the maximum weight path of length i can be found by extending maximum weight paths of length i-1. This approach is analogous to a k-iteration Bellman-Ford algorithm.
Algorithm
- Initialize a 2D array
dp[k+1][n]with -1. - Set the base case:
dp[0][j] = 0for alljfrom 0 ton-1. - Loop for
ifrom 1 tok(number of edges): -
Inside, loop through each edge `[u, v, w]` in `edges`: -
If a path of `i-1` edges to `u` exists (`dp[i-1][u] != -1`), update the path to `v`: -
`dp[i][v] = max(dp[i][v], dp[i-1][u] + w)`. - After the loops, find the maximum value in
dp[k]that is less thant. - Return this maximum value, or -1 if none is found.
Walkthrough
We define a 2D DP array, dp[i][j], to store the maximum weight of a path that has exactly i edges and ends at node j.
- State:
dp[i][j]= maximum weight of a path withiedges ending at nodej. - Base Case: For a path with 0 edges, the weight is 0. We can consider being at any node
jas a 0-length path starting and ending atj. Thus, we initializedp[0][j] = 0for alljfrom 0 ton-1. All otherdpentries are initialized to -1 to signify impossibility. - Recurrence Relation: To compute
dp[i][v], we look at all incoming edges(u, v)with weightw. A path ofiedges tovcan be formed by taking a path ofi-1edges touand then traversing the edge(u, v). The new weight would bedp[i-1][u] + w. We take the maximum over all such predecessorsu.dp[i][v] = max(dp[i][v], dp[i-1][u] + w) - Iteration: We iterate from
i = 1tok. In each iteration, we loop through all edges(u, v, w)and updatedp[i][v]based ondp[i-1][u]. - Final Result: After filling the table, the
k-th row,dp[k], contains the maximum weights for all paths of lengthk. We iterate throughdp[k][j]for allj, find the maximum value that is strictly less thant, and return it. If no such value exists, we return -1.
import java.util.Arrays; class Solution { public int maxWeightedKEdgePath(int n, int[][] edges, int k, int t) { long[][] dp = new long[k + 1][n]; for (long[] row : dp) { Arrays.fill(row, -1); } for (int j = 0; j < n; j++) { dp[0][j] = 0; } for (int i = 1; i <= k; i++) { for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; int w = edge[2]; if (dp[i - 1][u] != -1) { dp[i][v] = Math.max(dp[i][v], dp[i - 1][u] + w); } } } long maxWeight = -1; for (int j = 0; j < n; j++) { if (dp[k][j] != -1 && dp[k][j] < t) { maxWeight = Math.max(maxWeight, dp[k][j]); } } return (int) maxWeight; }}Complexity
Time
O(k * E), where `E` is the number of edges. We iterate `k` times, and in each iteration, we process all `E` edges.
Space
O(k * n) to store the DP table.
Trade-offs
Pros
Guaranteed to find the optimal solution.
Efficient enough to pass the given constraints.
Cons
Requires O(k * n) space, which can be large if
kandnare big.
The standard dynamic programming approach can be optimized in terms of space. Notice that to compute the maximum weights for paths of length i, we only need the results for paths of length i-1. This allows us to reduce the space complexity from O(k * n) to O(n).
Algorithm
- Initialize a 1D array
dpof sizenwith 0s (for paths of length 0). - Loop for
ifrom 1 tok: -
Create a new array `next_dp` of size `n` and initialize it with -1. -
Loop through each edge `[u, v, w]`: -
If `dp[u]` is not -1, update `next_dp[v] = max(next_dp[v], dp[u] + w)`. -
After processing all edges, replace `dp` with `next_dp`. - After the main loop, find the maximum value in the final
dparray that is less thant. - Return this maximum value, or -1.
Walkthrough
Instead of maintaining the entire k x n DP table, we only need two 1D arrays: one to store the results from the previous step (i-1) and one for the current step (i).
- State: We use two arrays,
dp(for stepi-1) andnext_dp(for stepi), both of sizen. - Base Case: The
dparray is initialized for 0 edges.dp[j] = 0for allj. - Iteration: We loop
ifrom 1 tok. In each iteration:- Initialize
next_dpwith -1. - Iterate through all edges
(u, v, w). - If a path to
uexisted in the previous step (dp[u] != -1), we update the potential path tovin the current step:next_dp[v] = max(next_dp[v], dp[u] + w). - After iterating through all edges,
next_dpcontains the results foriedges. We then updatedp = next_dpfor the next iteration.
- Initialize
- Final Result: After
kiterations, thedparray holds the maximum weights for paths of lengthk. We find the maximum value in this array that is less thant.
import java.util.Arrays; class Solution { public int maxWeightedKEdgePath(int n, int[][] edges, int k, int t) { long[] dp = new long[n]; // Base case for 0 edges is implicitly handled as the array is initialized to 0. for (int i = 1; i <= k; i++) { long[] next_dp = new long[n]; Arrays.fill(next_dp, -1); for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; int w = edge[2]; // dp[u] corresponds to the max weight of a path with i-1 edges ending at u. if (dp[u] != -1) { next_dp[v] = Math.max(next_dp[v], dp[u] + w); } } dp = next_dp; } long maxWeight = -1; for (long weight : dp) { if (weight != -1 && weight < t) { maxWeight = Math.max(maxWeight, weight); } } return (int) maxWeight; }}Complexity
Time
O(k * E). The time complexity remains the same as the unoptimized DP approach.
Space
O(n). We only need two arrays of size `n` to store the DP states for the current and previous number of edges.
Trade-offs
Pros
Most memory-efficient solution.
Maintains the same time efficiency as the standard DP approach.
Cons
Slightly more complex to implement due to the need to swap or copy arrays in each iteration.
Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.