Min Cost Path (original) (raw)
You are given a 2D matrix cost[][]
of dimensions m × n
, where each cell represents the cost of traversing through that position. Your goal is to determine the minimum cost required to reach the bottom-right cell (
m-1, n-1
)
starting from the top-left cell (
0,0
)
.
The total cost of a path is the sum of all cell values along the path, including both the starting and ending positions. From any cell (i, j)
, you can move in the following three directions:
- Right
(i, j+1)
- Down
(i+1, j)
- Diagonal
(i+1, j+1)
Find the minimum cost path from (0,0)
to (m-1, n-1)
, ensuring that movement constraints are followed.
**Example:
**Input:
**Output: 8
**Explanation: The path with minimum cost is highlighted in the following figure. The path is (0, 0) --> (0, 1) --> (1, 2) --> (2, 2). The cost of the path is 8 (1 + 2 + 2 + 3).
[Naive Approach] - Using Recursion - O(3 ^ (m * n)) Time and O(1) Space
The idea is to recursively generate all possible paths from top-left cell to bottom-right cell, and find the path with minimum cost. For the recursive approach, there ar**e three potential cases for each cell in the grid (for any cell at position (m, n)):
- The **cost to reach the **current cell can be calculated by **moving left, i.e., **from cell (m, n-1).
- The **cost to reach the current cell can also be calculated by **moving up, i.e., **from cell (m-1, n).
- The **cost can also be calculated by **moving diagonally, i.e., **from cell (m-1, n-1).
Mathematically, the **recurrence relation will look like:
minCost(cost, m, n) = cost[m][n] + min(minCost(cost, m, n-1), minCost(cost, m-1, n), minCost(cost, m-1, n-1))
**Base Cases:
- if m < 0 or n < 0 (out of bounds) minCost(cost, m, n) = INT_MAX
- minCost(cost, 0, 0) = cost[0][0] as the starting point.
Below is given the **implementation:
C++ `
#include <bits/stdc++.h> using namespace std;
// Function to return the cost of the minimum cost path // from (0,0) to (m - 1, n - 1) in a cost matrix int findMinCost(vector<vector>& cost, int x, int y) { int m = cost.size(); int n = cost[0].size();
// If indices are out of bounds, return a large value
if (x >= m || y >= m) {
return INT_MAX;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return cost[x][y] + min({findMinCost(cost, x, y + 1),
findMinCost(cost, x + 1, y),
findMinCost(cost, x + 1, y + 1)});
}
// function to find the minimum cost path // to reach (m - 1, n - 1) from (0, 0) int minCost(vector<vector>& cost) { return findMinCost(cost, 0, 0); }
int main() {
vector<vector<int>> cost = {
{ 1, 2, 3 },
{ 4, 8, 2 },
{ 1, 5, 3 }
};
cout << minCost(cost);
return 0;
}
Java
import java.util.*;
class GfG {
// Function to return the cost of the minimum cost path
// from (0,0) to (m - 1, n - 1) in a cost matrix
static int findMinCost(int[][] cost, int x, int y) {
int m = cost.length;
int n = cost[0].length;
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return Integer.MAX_VALUE;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return cost[x][y] + Math.min(
Math.min(findMinCost(cost, x, y + 1),
findMinCost(cost, x + 1, y)),
findMinCost(cost, x + 1, y + 1));
}
// function to find the minimum cost path
// to reach (m - 1, n - 1) from (0, 0)
static int minCost(int[][] cost) {
return findMinCost(cost, 0, 0);
}
public static void main(String[] args) {
int[][] cost = {
{ 1, 2, 3 },
{ 4, 8, 2 },
{ 1, 5, 3 }
};
System.out.println(minCost(cost));
}
}
Python
import sys
Function to return the cost of the minimum cost path
from (0,0) to (m - 1, n - 1) in a cost matrix
def findMinCost(cost, x, y): m = len(cost) n = len(cost[0])
# If indices are out of bounds, return a large value
if x >= m or y >= n:
return sys.maxsize
# Base case: bottom cell
if x == m - 1 and y == n - 1:
return cost[x][y]
# Recursively calculate minimum cost from
# all possible paths
return cost[x][y] + min(findMinCost(cost, x, y + 1),
findMinCost(cost, x + 1, y),
findMinCost(cost, x + 1, y + 1))
function to find the minimum cost path
to reach (m - 1, n - 1) from (0, 0)
def minCost(cost): return findMinCost(cost, 0, 0)
cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ]
print(minCost(cost))
C#
using System;
class GfG {
// Function to return the cost of the minimum cost path
// from (0,0) to (m - 1, n - 1) in a cost matrix
static int findMinCost(int[,] cost, int x, int y) {
int m = cost.GetLength(0);
int n = cost.GetLength(1);
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return int.MaxValue;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x, y];
}
// Recursively calculate minimum cost from
// all possible paths
return cost[x, y] + Math.Min(
Math.Min(findMinCost(cost, x, y + 1),
findMinCost(cost, x + 1, y)),
findMinCost(cost, x + 1, y + 1));
}
// function to find the minimum cost path
// to reach (m - 1, n - 1) from (0, 0)
static int minCost(int[,] cost) {
return findMinCost(cost, 0, 0);
}
public static void Main() {
int[,] cost = {
{ 1, 2, 3 },
{ 4, 8, 2 },
{ 1, 5, 3 }
};
Console.WriteLine(minCost(cost));
}
}
JavaScript
// Function to return the cost of the minimum cost path // from (0,0) to (m - 1, n - 1) in a cost matrix function findMinCost(cost, x, y) { let m = cost.length; let n = cost[0].length;
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return Number.MAX_SAFE_INTEGER;
}
// Base case: bottom cell
if (x === m - 1 && y === n - 1) {
return cost[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return cost[x][y] + Math.min(
findMinCost(cost, x, y + 1),
findMinCost(cost, x + 1, y),
findMinCost(cost, x + 1, y + 1));
}
// function to find the minimum cost path // to reach (m - 1, n - 1) from (0, 0) function minCost(cost) { return findMinCost(cost, 0, 0); }
let cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ];
console.log(minCost(cost));
`
[Expected Approach - 1] - Using Top-Down DP (Memoization) - O(m*n) Time and O(m*n) Space
****1. Optimal Substructure:**The minimum cost to reach any cell in the grid can be derived from smaller subproblems (i.e., the cost to reach neighboring cells). Specifically, the recursive relation will look like:
minCost(cost, m, n) = cost[m][n] + min(minCost(cost, m, n-1), minCost(cost, m-1, n), minCost(cost, m-1, n-1))
If **the last element (i.e., cell (m - 1, n - 1)) is reached, the **cost to reach it will be the value of the cell plus the **minimum cost to reach one of its valid neighboring cells ****(left, up, or diagonal).**
**2. Overlapping Subproblems:
In the **recursive approach, subproblems are computed multiple times. For example, when computing the minimum cost from (m, n), we may need to compute the cost for (m-1, n) multiple times. This repetition can be avoided by storing the results of subproblems in a memoization table.
memo[m][n] = cost[m][n] + min(minCost(cost, m, n-1), minCost(cost, m-1, n), minCost(cost, m-1, n-1))
Steps to implement Memoization:
- Create a **2D memo table of size ****(m x n)** to store the computed values, initialized to -1 to indicate uncomputed subproblems.
- If we are at the last cell (m - 1, n - 1), return the value of cost[m - 1][n - 1].
- Before computing the result for any cell (m, n), check if the value at **memo[m][n] is already computed. If it is, return the **stored value.
- If the value is not computed, **recursively calculate the minimum cost and store it in memo[m][n].
- Finally, return the value in memo[0][0] for the minimum cost to reach the target **cell (m-1, n-1).
Below is given the **implementation:
C++ `
#include <bits/stdc++.h> using namespace std;
// Function to return the cost of the minimum cost path // from (0,0) to (m - 1, n - 1) in a cost matrix int findMinCost(vector<vector>& cost, int x, int y, vector<vector> &memo) { int m = cost.size(); int n = cost[0].size();
// If indices are out of bounds, return a large value
if (x >= m || y >= m) {
return INT_MAX;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x][y];
}
// Check if the result is already computed
if (memo[x][y] != -1) {
return memo[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return memo[x][y] = cost[x][y] +
min({findMinCost(cost, x, y + 1, memo),
findMinCost(cost, x + 1, y, memo),
findMinCost(cost, x + 1, y + 1, memo)});
}
// function to find the minimum cost path // to reach (m - 1, n - 1) from (0, 0) int minCost(vector<vector>& cost) { int m = cost.size(); int n = cost[0].size();
// create 2d array to store the minimum cost path
vector<vector<int>> memo(m, vector<int>(n, -1));
return findMinCost(cost, 0, 0, memo);
}
int main() { vector<vector> cost = { { 1, 2, 3 }, { 4, 8, 2 }, { 1, 5, 3 } }; cout << minCost(cost); return 0; }
Java
import java.util.*;
class GfG {
// Function to return the cost of the minimum cost path
// from (0,0) to (m - 1, n - 1) in a cost matrix
static int findMinCost(int[][] cost, int x,
int y, int[][] memo) {
int m = cost.length;
int n = cost[0].length;
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return Integer.MAX_VALUE;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x][y];
}
// Check if the result is already computed
if (memo[x][y] != -1) {
return memo[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return memo[x][y] = cost[x][y] +
Math.min(Math.min(findMinCost(cost, x, y + 1, memo),
findMinCost(cost, x + 1, y, memo)),
findMinCost(cost, x + 1, y + 1, memo));
}
// function to find the minimum cost path
// to reach (m - 1, n - 1) from (0, 0)
static int minCost(int[][] cost) {
int m = cost.length;
int n = cost[0].length;
// create 2d array to store the minimum cost path
int[][] memo = new int[m][n];
for (int[] row : memo) {
Arrays.fill(row, -1);
}
return findMinCost(cost, 0, 0, memo);
}
public static void main(String[] args) {
int[][] cost = {
{ 1, 2, 3 },
{ 4, 8, 2 },
{ 1, 5, 3 }
};
System.out.println(minCost(cost));
}
}
Python
import sys
Function to return the cost of the minimum cost path
from (0,0) to (m - 1, n - 1) in a cost matrix
def findMinCost(cost, x, y, memo): m = len(cost) n = len(cost[0])
# If indices are out of bounds, return a large value
if x >= m or y >= n:
return sys.maxsize
# Base case: bottom cell
if x == m - 1 and y == n - 1:
return cost[x][y]
# Check if the result is already computed
if memo[x][y] != -1:
return memo[x][y]
# Recursively calculate minimum cost from
# all possible paths
memo[x][y] = cost[x][y] + min(
findMinCost(cost, x, y + 1, memo),
findMinCost(cost, x + 1, y, memo),
findMinCost(cost, x + 1, y + 1, memo))
return memo[x][y]
function to find the minimum cost path
to reach (m - 1, n - 1) from (0, 0)
def minCost(cost): m = len(cost) n = len(cost[0])
# create 2d array to store the minimum cost path
memo = [[-1] * n for _ in range(m)]
return findMinCost(cost, 0, 0, memo)
cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ]
print(minCost(cost))
C#
using System;
class GfG {
// Function to return the cost of the minimum cost path
// from (0,0) to (m - 1, n - 1) in a cost matrix
static int findMinCost(int[,] cost, int x,
int y, int[,] memo) {
int m = cost.GetLength(0);
int n = cost.GetLength(1);
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return int.MaxValue;
}
// Base case: bottom cell
if (x == m - 1 && y == n - 1) {
return cost[x, y];
}
// Check if the result is already computed
if (memo[x, y] != -1) {
return memo[x, y];
}
// Recursively calculate minimum cost from
// all possible paths
return memo[x, y] = cost[x, y] +
Math.Min(Math.Min(findMinCost(cost, x, y + 1, memo),
findMinCost(cost, x + 1, y, memo)),
findMinCost(cost, x + 1, y + 1, memo));
}
// function to find the minimum cost path
// to reach (m - 1, n - 1) from (0, 0)
static int minCost(int[,] cost) {
int m = cost.GetLength(0);
int n = cost.GetLength(1);
// create 2d array to store the minimum cost path
int[,] memo = new int[m, n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
memo[i, j] = -1;
}
}
return findMinCost(cost, 0, 0, memo);
}
public static void Main() {
int[,] cost = {
{ 1, 2, 3 },
{ 4, 8, 2 },
{ 1, 5, 3 }
};
Console.WriteLine(minCost(cost));
}
}
JavaScript
// Function to return the cost of the minimum cost path // from (0,0) to (m - 1, n - 1) in a cost matrix function findMinCost(cost, x, y, memo) { let m = cost.length; let n = cost[0].length;
// If indices are out of bounds, return a large value
if (x >= m || y >= n) {
return Number.MAX_SAFE_INTEGER;
}
// Base case: bottom cell
if (x === m - 1 && y === n - 1) {
return cost[x][y];
}
// Check if the result is already computed
if (memo[x][y] !== -1) {
return memo[x][y];
}
// Recursively calculate minimum cost from
// all possible paths
return memo[x][y] = cost[x][y] + Math.min(
findMinCost(cost, x, y + 1, memo),
findMinCost(cost, x + 1, y, memo),
findMinCost(cost, x + 1, y + 1, memo));
}
// function to find the minimum cost path // to reach (m - 1, n - 1) from (0, 0) function minCost(cost) { let m = cost.length; let n = cost[0].length;
// create 2d array to store the minimum cost path
let memo = Array.from({ length: m }, () => Array(n).fill(-1));
return findMinCost(cost, 0, 0, memo);
}
let cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ];
console.log(minCost(cost));
`
[Expected Approach - 2] - Using Bottom-Up DP (Tabulation) -O(m * n) **Time and O(m * n) Space
The approach here is similar to the **recursive one but instead of breaking down the problem recursively, we iteratively build up the solution by calculating it in a **bottom-up manner. We create a **2D array dp of **size m*n where dp[i][j] represents the **minimum cost to reach cell (i, j).
**Dynamic Programming Relation:
Initialize the base case: **dp[0][0] = cost[0][0]
- For the first row (dp[0][j]), we can only move from the left: dp[0][j] = dp[0][j - 1] + cost[0][j] for j > 0
- For the first column (dp[i][0]), we can only move from the top: dp[i][0] = dp[i - 1][0] + cost[i][0] for i > 0
For the rest of the cells, we calculate the minimum cost by considering the **minimum cost from three directions: from the **left, from **above, and from the **diagonal:
- **dp[i][j] = cost[i][j] + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])
This formula ensures that at each step, we are choosing the **minimum cost path to reach the current cell.
Below is given the **implementation:
C++ `
// C++ implementation to find the minimum cost path // using Tabulation (Dynamic Programming) #include <bits/stdc++.h> using namespace std;
int minCost(vector<vector>& cost) { int m = cost.size(); int n = cost[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
// Initialize the base cell
dp[0][0] = cost[0][0];
// Fill the first row
for (int j = 1; j < n; j++) {
dp[0][j] = dp[0][j - 1] + cost[0][j];
}
// Fill the first column
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + cost[i][0];
}
// Fill the rest of the dp table
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = cost[i][j] + min({dp[i - 1][j],
dp[i][j - 1], dp[i - 1][j - 1]});
}
}
return dp[m - 1][n - 1];
}
int main() {
vector<vector<int>> cost = {
{1, 2, 3},
{4, 8, 2},
{1, 5, 3}
};
cout << minCost(cost);
return 0;
}
Java
// Java implementation to find the minimum cost path // using Tabulation (Dynamic Programming) import java.util.ArrayList; import java.util.List;
class GfG {
static int minCost(List<List<Integer>> cost) {
int m = cost.size();
int n = cost.get(0).size();
int[][] dp = new int[m][n];
// Initialize the base cell
dp[0][0] = cost.get(0).get(0);
// Fill the first row
for (int j = 1; j < n; j++) {
dp[0][j] = dp[0][j - 1] + cost.get(0).get(j);
}
// Fill the first column
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + cost.get(i).get(0);
}
// Fill the rest of the dp table
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = cost.get(i).get(j)
+ Math.min(dp[i - 1][j],
Math.min(dp[i][j - 1], dp[i - 1][j - 1]));
}
}
// Minimum cost to reach the bottom-right cell
return dp[m - 1][n - 1];
}
public static void main(String[] args) {
List<List<Integer>> cost = new ArrayList<>();
cost.add(List.of(1, 2, 3));
cost.add(List.of(4, 8, 2));
cost.add(List.of(1, 5, 3));
System.out.println(minCost(cost));
}
}
Python
Python implementation to find the minimum cost path
using Tabulation (Dynamic Programming)
def mincost(cost): m = len(cost) n = len(cost[0]) dp = [[0] * n for _ in range(m)]
# Initialize the base cell
dp[0][0] = cost[0][0]
# Fill the first row
for j in range(1, n):
dp[0][j] = dp[0][j - 1] + cost[0][j]
# Fill the first column
for i in range(1, m):
dp[i][0] = dp[i - 1][0] + cost[i][0]
# Fill the rest of the dp table
for i in range(1, m):
for j in range(1, n):
dp[i][j] = cost[i][j] \
+ min(dp[i - 1][j], \
dp[i][j - 1], dp[i - 1][j - 1])
# Minimum cost to reach the
# bottom-right cell
return dp[m - 1][n - 1]
if name == "main":
cost = [
[1, 2, 3],
[4, 8, 2],
[1, 5, 3]
]
print(mincost(cost))
C#
// C# implementation to find the minimum cost path // using Tabulation (Dynamic Programming) using System; using System.Collections.Generic;
class GfG {
static int MinCost(List<List<int>> cost) {
int m = cost.Count;
int n = cost[0].Count;
int[,] dp = new int[m, n];
// Initialize the base cell
dp[0, 0] = cost[0][0];
// Fill the first row
for (int j = 1; j < n; j++) {
dp[0, j] = dp[0, j - 1] + cost[0][j];
}
// Fill the first column
for (int i = 1; i < m; i++) {
dp[i, 0] = dp[i - 1, 0] + cost[i][0];
}
// Fill the rest of the dp table
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i, j] = cost[i][j]
+ Math.Min(dp[i - 1, j],
Math.Min(dp[i, j - 1], dp[i - 1, j - 1]));
}
}
// Minimum cost to reach the
// bottom-right cell
return dp[m - 1, n - 1];
}
static void Main() {
List<List<int>> cost = new List<List<int>> {
new List<int> { 1, 2, 3 },
new List<int> { 4, 8, 2 },
new List<int> { 1, 5, 3 }
};
Console.WriteLine(MinCost(cost));
}
}
JavaScript
// JavaScript implementation to find the minimum cost path // using Tabulation (Dynamic Programming)
function minCost(cost) {
const m = cost.length;
const n = cost[0].length;
const dp = Array.from({ length: m }, () => Array(n).fill(0));
// Initialize the base cell
dp[0][0] = cost[0][0];
// Fill the first row
for (let j = 1; j < n; j++) {
dp[0][j] = dp[0][j - 1] + cost[0][j];
}
// Fill the first column
for (let i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + cost[i][0];
}
// Fill the rest of the dp table
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
dp[i][j] = cost[i][j]
+ Math.min(dp[i - 1][j],
dp[i][j - 1], dp[i - 1][j - 1]);
}
}
// Minimum cost to reach the bottom-right cell
return dp[m - 1][n - 1];
}
const cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ]; console.log(minCost(cost));
`
[Optimal Approach] - Using Space Optimized DP - O(m * n) Time and O(n) Space
In the previous approach, we used a **2D dp table to store the **minimum cost at each cell. However, we can optimize the space complexity by observing that for calculating the **current state, we only need the values from the **previous row. Therefore, there is no need to store the entire dp table, and we can optimize the **space to O(n) by only keeping track of the current and previous rows.
Below is given the **implementation:
C++ `
// C++ implementation to find the minimum cost path // using Space Optimization #include <bits/stdc++.h> using namespace std;
int minCost(vector<vector> &cost) {
int m = cost.size();
int n = cost[0].size();
// 1D dp array to store the minimum cost
// of the current row
vector<int> dp(n, 0);
// Initialize the base cell
dp[0] = cost[0][0];
// Fill the first row
for (int j = 1; j < n; j++) {
dp[j] = dp[j - 1] + cost[0][j];
}
// Fill the rest of the rows
for (int i = 1; i < m; i++) {
// Store the previous value of dp[j-1]
// (for diagonal handling)
int prev = dp[0];
// Update the first column (only depends on
// the previous row)
dp[0] = dp[0] + cost[i][0];
for (int j = 1; j < n; j++) {
// Store the current dp[j] before updating it
int temp = dp[j];
// Update dp[j] using the minimum of the
// top, left, and diagonal cells
dp[j] = cost[i][j] + min({dp[j], dp[j - 1], prev});
// Update prev to be the old dp[j] for the
// diagonal calculation in the next iteration
prev = temp;
}
}
// The last cell contains the
// minimum cost path
return dp[n - 1];
}
int main() { vector<vector> cost = {{1, 2, 3}, {4, 8, 2}, {1, 5, 3}};
cout << minCost(cost) << endl;
return 0;
}
Java
// Java implementation to find the minimum cost path // using Space Optimization import java.util.*;
class GfG {
static int minCost(int[][] cost) {
int m = cost.length;
int n = cost[0].length;
// 1D dp array to store the minimum cost of the
// current row
int[] dp = new int[n];
// Initialize the base cell
dp[0] = cost[0][0];
// Fill the first row
for (int j = 1; j < n; j++) {
dp[j] = dp[j - 1] + cost[0][j];
}
// Fill the rest of the rows
for (int i = 1; i < m; i++) {
// Store the previous value of dp[j-1] (for
// diagonal handling)
int prev = dp[0];
// Update the first column (only depends on the
// previous row)
dp[0] = dp[0] + cost[i][0];
for (int j = 1; j < n; j++) {
// Store the current dp[j] before updating
// it
int temp = dp[j];
// Update dp[j] using the minimum of the
// top, left, and diagonal cells
dp[j]
= cost[i][j]
+ Math.min(dp[j],
Math.min(dp[j - 1], prev));
// Update prev to be the old dp[j] for the
// diagonal calculation in the next
// iteration
prev = temp;
}
}
// The last cell contains the minimum cost path
return dp[n - 1];
}
public static void main(String[] args) {
int[][] cost
= { { 1, 2, 3 }, { 4, 8, 2 }, { 1, 5, 3 } };
System.out.println(minCost(cost));
}
}
Python
Python implementation to find the minimum cost path
using Space Optimization
def minCost(cost): m = len(cost) n = len(cost[0])
# 1D dp array to store the minimum
# cost of the current row
dp = [0] * n
# Initialize the base cell
dp[0] = cost[0][0]
# Fill the first row
for j in range(1, n):
dp[j] = dp[j - 1] + cost[0][j]
# Fill the rest of the rows
for i in range(1, m):
# Store the previous value of dp[j-1]
# (for diagonal handling)
prev = dp[0]
# Update the first column (only depends
# on the previous row)
dp[0] = dp[0] + cost[i][0]
for j in range(1, n):
# Store the current dp[j] before
# updating it
temp = dp[j]
# Update dp[j] using the minimum of the top,
# left, and diagonal cells
dp[j] = cost[i][j] + min(dp[j], dp[j - 1], prev)
# Update prev to be the old dp[j] for the
# diagonal calculation in the next iteration
prev = temp
# The last cell contains the minimum
# cost path
return dp[n - 1]
cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ]
print(minCost(cost))
C#
// C# implementation to find the minimum cost path // using Space Optimization using System;
class GfG { static int MinCost(int[, ] cost) { int m = cost.GetLength(0); int n = cost.GetLength(1);
// 1D dp array to store the minimum cost of the
// current row
int[] dp = new int[n];
// Initialize the base cell
dp[0] = cost[0, 0];
// Fill the first row
for (int j = 1; j < n; j++) {
dp[j] = dp[j - 1] + cost[0, j];
}
// Fill the rest of the rows
for (int i = 1; i < m; i++) {
// Store the previous value of dp[j-1] (for
// diagonal handling)
int prev = dp[0];
// Update the first column (only depends on the
// previous row)
dp[0] = dp[0] + cost[i, 0];
for (int j = 1; j < n; j++) {
// Store the current dp[j] before updating
// it
int temp = dp[j];
// Update dp[j] using the minimum of the
// top, left, and diagonal cells
dp[j]
= cost[i, j]
+ Math.Min(dp[j],
Math.Min(dp[j - 1], prev));
// Update prev to be the old dp[j] for the
// diagonal calculation in the next
// iteration
prev = temp;
}
}
// The last cell contains the minimum cost path
return dp[n - 1];
}
static void Main(string[] args) {
int[, ] cost
= { { 1, 2, 3 }, { 4, 8, 2 }, { 1, 5, 3 } };
Console.WriteLine(MinCost(cost));
}
}
JavaScript
// JavaScript implementation to find the minimum cost path // using Space Optimization function minCost(cost) {
const m = cost.length;
const n = cost[0].length;
// 1D dp array to store the minimum cost of the current
// row
let dp = new Array(n);
// Initialize the base cell
dp[0] = cost[0][0];
// Fill the first row
for (let j = 1; j < n; j++) {
dp[j] = dp[j - 1] + cost[0][j];
}
// Fill the rest of the rows
for (let i = 1; i < m; i++) {
// Store the previous value of dp[j-1] (for diagonal
// handling)
let prev = dp[0];
// Update the first column (only depends on the
// previous row)
dp[0] = dp[0] + cost[i][0];
for (let j = 1; j < n; j++) {
// Store the current dp[j] before updating it
let temp = dp[j];
// Update dp[j] using the minimum of the top,
// left, and diagonal cells
dp[j] = cost[i][j]
+ Math.min(dp[j],
Math.min(dp[j - 1], prev));
// Update prev to be the old dp[j] for the
// diagonal calculation in the next iteration
prev = temp;
}
}
// The last cell contains the minimum cost path
return dp[n - 1];
}
const cost = [ [ 1, 2, 3 ], [ 4, 8, 2 ], [ 1, 5, 3 ] ]; console.log(minCost(cost));
`
[Alternate Less Efficient Approach] - Using Dijkstra's Algorithm - O((m * n) * log(m * n)) Time and O(m * n) Space
The idea is to apply Dijskra's Algorithm to find the **minimum cost path from the **top-left to the bottom-right corner of the grid. Each cell is treated as a node and each move between adjacent cells has a cost. We use a min-heap to always expand the least costly path first.
C++ `
// C++ implementation to find minimum cost path // using Dijstra's Algoritms #include <bits/stdc++.h> using namespace std;
int minCost(vector<vector> &cost) {
int m = cost.size();
int n = cost[0].size();
// Directions for moving down, right, and diagonal
vector<pair<int, int>> directions =
{{1, 0}, {0, 1}, {1, 1}};
// Min-heap (priority queue) for Dijkstra's algorithm
priority_queue<vector<int>,
vector<vector<int>>, greater<vector<int>>> pq;
// Distance matrix to store the minimum
// cost to reach each cell
vector<vector<int>> dist(m, vector<int>(n, INT_MAX));
dist[0][0] = cost[0][0];
pq.push({cost[0][0], 0, 0});
// Prim's algorithm
while (!pq.empty()) {
vector<int> curr = pq.top();
pq.pop();
int x = curr[1];
int y = curr[2];
// If we reached the bottom-right
// corner, return the cost
if (x == m - 1 && y == n - 1) {
return dist[x][y];
}
// Explore the neighbors
for (auto &dir : directions) {
int newX = x + dir.first;
int newY = y + dir.second;
// Ensure the new cell is within bounds
if (newX < m && newY < n) {
// Relaxation step
if (dist[newX][newY] > dist[x][y] + cost[newX][newY]) {
dist[newX][newY] = dist[x][y] + cost[newX][newY];
pq.push({dist[newX][newY], newX, newY});
}
}
}
}
return dist[m - 1][n - 1];
}
int main() { vector<vector> cost = { {1, 2, 3}, {4, 8, 2}, {1, 5, 3} }; cout << minCost(cost); return 0; }
Java
import java.util.*;
class GfG {
int minCost(int[][] cost) {
int m = cost.length;
int n = cost[0].length;
// Directions for moving down, right, and diagonal
int[][] directions = {{1, 0}, {0, 1}, {1, 1}};
// Min-heap (priority queue) for Dijkstra's algorithm
PriorityQueue<int[]> pq =
new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
// Distance matrix to store the minimum
// cost to reach each cell
int[][] dist = new int[m][n];
for (int[] row : dist) {
Arrays.fill(row, Integer.MAX_VALUE);
}
dist[0][0] = cost[0][0];
pq.add(new int[]{cost[0][0], 0, 0});
// Prim's algorithm
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int x = curr[1];
int y = curr[2];
// If we reached the bottom-right
// corner, return the cost
if (x == m - 1 && y == n - 1) {
return dist[x][y];
}
// Explore the neighbors
for (int[] dir : directions) {
int newX = x + dir[0];
int newY = y + dir[1];
// Ensure the new cell is within bounds
if (newX < m && newY < n) {
// Relaxation step
if (dist[newX][newY] > dist[x][y] + cost[newX][newY]) {
dist[newX][newY] = dist[x][y] + cost[newX][newY];
pq.add(new int[]{dist[newX][newY], newX, newY});
}
}
}
}
return dist[m - 1][n - 1];
}
public static void main(String[] args) {
int[][] cost = {
{1, 2, 3},
{4, 8, 2},
{1, 5, 3}
};
GfG obj = new GfG();
System.out.println(obj.minCost(cost));
}
}
Python
import heapq
def minCost(cost):
m = len(cost)
n = len(cost[0])
# Directions for moving down, right, and diagonal
directions = [(1, 0), (0, 1), (1, 1)]
# Min-heap (priority queue) for Dijkstra's algorithm
pq = []
# Distance matrix to store the minimum
# cost to reach each cell
dist = [[float('inf')] * n for _ in range(m)]
dist[0][0] = cost[0][0]
heapq.heappush(pq, (cost[0][0], 0, 0))
# Prim's algorithm
while pq:
curr = heapq.heappop(pq)
x = curr[1]
y = curr[2]
# If we reached the bottom-right
# corner, return the cost
if x == m - 1 and y == n - 1:
return dist[x][y]
# Explore the neighbors
for dx, dy in directions:
newX = x + dx
newY = y + dy
# Ensure the new cell is within bounds
if newX < m and newY < n:
# Relaxation step
if dist[newX][newY] > dist[x][y] + cost[newX][newY]:
dist[newX][newY] = dist[x][y] + cost[newX][newY]
heapq.heappush(pq, (dist[newX][newY], newX, newY))
return dist[m - 1][n - 1]
cost = [ [1, 2, 3], [4, 8, 2], [1, 5, 3] ]
print(minCost(cost))
C#
using System; using System.Collections.Generic;
class GfG {
int minCost(int[,] cost) {
int m = cost.GetLength(0);
int n = cost.GetLength(1);
// Directions for moving down, right, and diagonal
int[,] directions = { {1, 0}, {0, 1}, {1, 1} };
// Min-heap (priority queue) for Dijkstra's algorithm
SortedSet<(int, int, int)> pq = new SortedSet<(int, int, int)>
(Comparer<(int, int, int)>.Create((a, b) =>
a.Item1 == b.Item1 ? (a.Item2 == b.Item2 ?
a.Item3 - b.Item3 : a.Item2 - b.Item2) : a.Item1 - b.Item1));
// Distance matrix to store the minimum
// cost to reach each cell
int[,] dist = new int[m, n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dist[i, j] = int.MaxValue;
}
}
dist[0, 0] = cost[0, 0];
pq.Add((cost[0, 0], 0, 0));
// Prim's algorithm
while (pq.Count > 0) {
var curr = pq.Min;
pq.Remove(curr);
int x = curr.Item2;
int y = curr.Item3;
// If we reached the bottom-right
// corner, return the cost
if (x == m - 1 && y == n - 1) {
return dist[x, y];
}
// Explore the neighbors
for (int i = 0; i < 3; i++) {
int newX = x + directions[i, 0];
int newY = y + directions[i, 1];
// Ensure the new cell is within bounds
if (newX < m && newY < n) {
// Relaxation step
if (dist[newX, newY] > dist[x, y] + cost[newX, newY]) {
dist[newX, newY] = dist[x, y] + cost[newX, newY];
pq.Add((dist[newX, newY], newX, newY));
}
}
}
}
return dist[m - 1, n - 1];
}
public static void Main() {
int[,] cost = {
{1, 2, 3},
{4, 8, 2},
{1, 5, 3}
};
GfG obj = new GfG();
Console.WriteLine(obj.minCost(cost));
}
}
JavaScript
function minCost(cost) {
let m = cost.length;
let n = cost[0].length;
// Directions for moving down, right, and diagonal
let directions = [[1, 0], [0, 1], [1, 1]];
// Min-heap (priority queue) for Dijkstra's algorithm
let pq = [];
// Distance matrix to store the minimum
// cost to reach each cell
let dist = Array.from({ length: m },
() => Array(n).fill(Infinity));
dist[0][0] = cost[0][0];
pq.push([cost[0][0], 0, 0]);
// Prim's algorithm
while (pq.length > 0) {
pq.sort((a, b) => a[0] - b[0]);
let [currCost, x, y] = pq.shift();
// If we reached the bottom-right
// corner, return the cost
if (x === m - 1 && y === n - 1) {
return dist[x][y];
}
// Explore the neighbors
for (let [dx, dy] of directions) {
let newX = x + dx;
let newY = y + dy;
// Ensure the new cell is within bounds
if (newX < m && newY < n) {
// Relaxation step
if (dist[newX][newY] > dist[x][y] + cost[newX][newY]) {
dist[newX][newY] = dist[x][y] + cost[newX][newY];
pq.push([dist[newX][newY], newX, newY]);
}
}
}
}
return dist[m - 1][n - 1];
}
console.log(minCost([[1, 2, 3], [4, 8, 2], [1, 5, 3]]));
`