Minimum cost to reach the last cell of a grid with directions
Last Updated :
23 Jul, 2025
Given a 2D matrix grid[][] of size M X N, where each cell of the grid has a character denoting the next cell we should visit we are at the current cell. The character at any cell can be:
- 'R' which means go to the cell to the right. (i.e from grid[i][j] to grid[i][j + 1])
- 'L' which means go to the cell to the left. (i.e go from grid[i][j] to grid[i][j - 1])
- 'D' which means go to the lower cell. (i.e go from grid[i][j] to grid[i + 1][j])
- 'U' which means go to the upper cell. (i.e go from grid[i][j] to grid[i - 1][j])
At any cell (i, j) we can either move in the direction denoted by character grid[i][j] with a cost of 0 or we can move in some other direction with a cost of 1. Starting from the cell (0, 0), the task is to reach cell (M-1, N-1) with minimum cost. The path does not have to be the shortest.
Note: The character may point to the outside of the grid as well.

Examples:
Input: N = 4, M = 4, grid[][]= {{'R', 'R', 'R', 'R'}, {'L', 'L', 'L', 'L'}, {'R', 'R', 'R', 'R'}, {'L', 'L', 'L', 'L'}}
Output: 3
Explanation: The path from (0, 0) to (3, 3) is:
- (0, 0) -> (0, 1) -> (0, 2) -> (0, 3), cost = 0
- (0, 3) -> (1, 3), cost = 1
- (1, 3) -> (1, 2) -> (1, 1) -> (1, 0), cost = 0
- (1, 0) -> (2, 0), cost = 1
- (2, 0) -> (2, 1) --> (2, 2) --> (2, 3), cost = 0
- (2, 3) -> (3, 3), cost = 1
The total cost = 0 + 1 + 0 + 1 + 0 + 1 = 3.
Input: N = 3, M = 3, grid = {{'R', 'R', 'D'}, {'D', 'L', 'L'}, {'R', 'R', 'U'}}
Output: 0
Explanation: The path from (0, 0) to (2, 2) is:
- (0, 0) -> (0, 1) -> (0, 2) -> (1, 2) -> (1, 1) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2), cost = 0
The total cost = 0.
Approach: To solve the problem, follow the below idea:
The problem can be solved using 0-1 BFS by considering the grid as a graph where edge weights are limited to 0 and 1 only. If we move in the same direction as denoted by the current cell, then the edge cost will be 0 otherwise if we move in any other direction, then the edge cost will be 1. Now, we can run a 0-1 BFS using a deque to find the minimum cost from cell (0, 0) to cell (M - 1, N - 1).
Step-by-step algorithm:
- Maintain a deque of pairs, say dq to store the row and column of the cells.
- Also maintain a cost[][] array, such that cost[i][j] stores the minimum cost to reach cell (i, j) starting from (0, 0).
- Push the cell (0, 0) to the dq.
- Iterate till dq is not empty:
- Pop the front element (r, c).
- For all the neighboring cells, push the cell to the front of dq if the neighboring cell is in the same direction as denoted by grid[r][c][/c], otherwise push the cell to the back of dq.
- Also, the cell will only be pushed if the cell has not been visited yet.
- We can keep track of the visited cells using the cost[][] array.
- Finally, return the value stored at cost[M - 1][N - 1].
Below is the implementation of the algorithm:
C++
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
// Method to check whether a cell is in the grid or not
bool isValid(int r, int c, int M, int N)
{
return r >= 0 && c >= 0 && r < M && c < N;
}
// Method to find the minimum cost to reach cell (M-1, N-1)
int minCost(vector<vector<char>>& grid)
{
// 0-1 BFS
deque<pair<int, int>> dq;
int M = grid.size(), N = grid[0].size();
// vector to store the minimum cost to reach a
// particular cell
vector<vector<int>> cost(M, vector<int>(N, 1e9));
cost[0][0] = 0;
dq.push_back({0, 0});
int dr[] = {0, 0, -1, 1};
int dc[] = {1, -1, 0, 0};
while (!dq.empty())
{
int r = dq.front().first;
int c = dq.front().second;
dq.pop_front();
for (int i = 0; i < 4; i++)
{
int new_r = r + dr[i];
int new_c = c + dc[i];
if (isValid(new_r, new_c, M, N))
{
int new_d = cost[r][c];
bool directionChange = false;
// If the next cell is in a different
// direction
if ((grid[r][c] != 'R' && dr[i] == 0 &&
dc[i] == 1) ||
(grid[r][c] != 'L' && dr[i] == 0 &&
dc[i] == -1) ||
(grid[r][c] != 'D' && dr[i] == 1 &&
dc[i] == 0) ||
(grid[r][c] != 'U' && dr[i] == -1 &&
dc[i] == 0))
{
new_d += 1;
directionChange = true;
}
// If the cell is unvisited
if (cost[new_r][new_c] > new_d)
{
cost[new_r][new_c] = new_d;
// If the next cell is in the same
// direction as written in grid[r][c]
if (directionChange)
{
dq.push_back({new_r, new_c});
}
// If the next cell is in a different
// direction as written in grid[r][c]
else
{
dq.push_front({new_r, new_c});
}
}
}
}
}
return cost[M - 1][N - 1];
}
int main()
{
vector<vector<char>> grid = {{'R', 'R', 'R', 'R'},
{'L', 'L', 'L', 'L'},
{'R', 'R', 'R', 'R'},
{'L', 'L', 'L', 'L'}};
cout << minCost(grid) << "\n";
return 0;
}
Java
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
// Method to check whether a cell is in the grid or not
static boolean isValid(int r, int c, int M, int N) {
return r >= 0 && c >= 0 && r < M && c < N;
}
// Method to find the minimum cost to reach cell (M-1, N-1)
static int minCost(char[][] grid) {
// 0-1 BFS
Deque<int[]> dq = new ArrayDeque<>();
int M = grid.length, N = grid[0].length;
// Array to store the minimum cost to reach a
// particular cell
int[][] cost = new int[M][N];
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
cost[i][j] = Integer.MAX_VALUE;
}
}
cost[0][0] = 0;
dq.addLast(new int[]{0, 0});
int[] dr = {0, 0, -1, 1};
int[] dc = {1, -1, 0, 0};
while (!dq.isEmpty()) {
int[] current = dq.pollFirst();
int r = current[0];
int c = current[1];
for (int i = 0; i < 4; i++) {
int new_r = r + dr[i];
int new_c = c + dc[i];
if (isValid(new_r, new_c, M, N)) {
int new_d = cost[r][c];
boolean directionChange = false;
// If the next cell is in a different direction
if ((grid[r][c] != 'R' && dr[i] == 0 && dc[i] == 1)
|| (grid[r][c] != 'L' && dr[i] == 0 && dc[i] == -1)
|| (grid[r][c] != 'D' && dr[i] == 1 && dc[i] == 0)
|| (grid[r][c] != 'U' && dr[i] == -1 && dc[i] == 0)) {
new_d += 1;
directionChange = true;
}
// If the cell is unvisited
if (cost[new_r][new_c] > new_d) {
cost[new_r][new_c] = new_d;
// If the next cell is in the same direction
// as written in grid[r][c]
if (directionChange) {
dq.addLast(new int[]{new_r, new_c});
}
// If the next cell is in a different
// direction as written in grid[r][c]
else {
dq.addFirst(new int[]{new_r, new_c});
}
}
}
}
}
return cost[M - 1][N - 1];
}
public static void main(String[] args) {
char[][] grid = {
{'R', 'R', 'R', 'R'},
{'L', 'L', 'L', 'L'},
{'R', 'R', 'R', 'R'},
{'L', 'L', 'L', 'L'}
};
System.out.println(minCost(grid));
}
}
// This code is contributed by rambabuguphka
C#
using System;
using System.Collections.Generic;
class Program
{
// Method to check whether a cell is in the grid or not
static bool IsValid(int r, int c, int M, int N)
{
return r >= 0 && c >= 0 && r < M && c < N;
}
// Method to find the minimum cost to reach cell (M-1, N-1)
static int MinCost(char[][] grid)
{
// 0-1 BFS
var dq = new Queue<Tuple<int, int>>();
int M = grid.Length, N = grid[0].Length;
// vector to store the minimum cost to reach a
// particular cell
var cost = new int[M][];
for (int i = 0; i < M; i++)
{
cost[i] = new int[N];
for (int j = 0; j < N; j++)
{
cost[i][j] = int.MaxValue;
}
}
cost[0][0] = 0;
dq.Enqueue(new Tuple<int, int>(0, 0));
int[] dr = { 0, 0, -1, 1 };
int[] dc = { 1, -1, 0, 0 };
while (dq.Count > 0)
{
var front = dq.Dequeue();
int r = front.Item1;
int c = front.Item2;
for (int i = 0; i < 4; i++)
{
int new_r = r + dr[i];
int new_c = c + dc[i];
if (IsValid(new_r, new_c, M, N))
{
int new_d = cost[r][c];
bool directionChange = false;
// If the next cell is in a different
// direction
if ((grid[r][c] != 'R' && dr[i] == 0 &&
dc[i] == 1) ||
(grid[r][c] != 'L' && dr[i] == 0 &&
dc[i] == -1) ||
(grid[r][c] != 'D' && dr[i] == 1 &&
dc[i] == 0) ||
(grid[r][c] != 'U' && dr[i] == -1 &&
dc[i] == 0))
{
new_d += 1;
directionChange = true;
}
// If the cell is unvisited
if (cost[new_r][new_c] > new_d)
{
cost[new_r][new_c] = new_d;
// If the next cell is in the same
// direction as written in grid[r][c]
if (directionChange)
{
dq.Enqueue(new Tuple<int, int>(new_r, new_c));
}
// If the next cell is in a different
// direction as written in grid[r][c]
else
{
dq.Enqueue(new Tuple<int, int>(new_r, new_c));
}
}
}
}
}
return cost[M - 1][N - 1];
}
static void Main()
{
char[][] grid = {
new char[] {'R', 'R', 'R', 'R'},
new char[] {'L', 'L', 'L', 'L'},
new char[] {'R', 'R', 'R', 'R'},
new char[] {'L', 'L', 'L', 'L'}
};
Console.WriteLine(MinCost(grid));
}
}
JavaScript
// Method to check whether a cell is in the grid or not
function isValid(r, c, M, N) {
return r >= 0 && c >= 0 && r < M && c < N;
}
// Method to find the minimum cost to reach cell (M-1, N-1)
function minCost(grid) {
// 0-1 BFS
const dq = [];
const M = grid.length;
const N = grid[0].length;
// matrix to store the minimum cost to reach a particular cell
const cost = Array.from({ length: M }, () => Array(N).fill(1e9));
cost[0][0] = 0;
dq.push([0, 0]);
const dr = [0, 0, -1, 1];
const dc = [1, -1, 0, 0];
while (dq.length > 0) {
const [r, c] = dq.shift();
for (let i = 0; i < 4; i++) {
const new_r = r + dr[i];
const new_c = c + dc[i];
if (isValid(new_r, new_c, M, N)) {
let new_d = cost[r][c];
let directionChange = false;
// If the next cell is in a different direction
if (
(grid[r][c] !== 'R' && dr[i] === 0 && dc[i] === 1) ||
(grid[r][c] !== 'L' && dr[i] === 0 && dc[i] === -1) ||
(grid[r][c] !== 'D' && dr[i] === 1 && dc[i] === 0) ||
(grid[r][c] !== 'U' && dr[i] === -1 && dc[i] === 0)
) {
new_d += 1;
directionChange = true;
}
// If the cell is unvisited
if (cost[new_r][new_c] > new_d) {
cost[new_r][new_c] = new_d;
// If the next cell is in the same direction
if (directionChange) {
dq.push([new_r, new_c]);
} else {
dq.unshift([new_r, new_c]);
}
}
}
}
}
return cost[M - 1][N - 1];
}
// Example usage
const grid = [
['R', 'R', 'R', 'R'],
['L', 'L', 'L', 'L'],
['R', 'R', 'R', 'R'],
['L', 'L', 'L', 'L']
];
console.log(minCost(grid));
Python3
from collections import deque
# Method to check whether a cell is in the grid or not
def is_valid(r, c, M, N):
return 0 <= r < M and 0 <= c < N
# Method to find the minimum cost to reach cell (M-1, N-1)
def min_cost(grid):
# 0-1 BFS
dq = deque()
M, N = len(grid), len(grid[0])
# list to store the minimum cost to reach a particular cell
cost = [[1e9] * N for _ in range(M)]
cost[0][0] = 0
dq.append((0, 0))
dr = [0, 0, -1, 1]
dc = [1, -1, 0, 0]
while dq:
r, c = dq.popleft()
for i in range(4):
new_r = r + dr[i]
new_c = c + dc[i]
if is_valid(new_r, new_c, M, N):
new_d = cost[r][c]
direction_change = False
# If the next cell is in a different direction
if ((grid[r][c] != 'R' and dr[i] == 0 and dc[i] == 1) or
(grid[r][c] != 'L' and dr[i] == 0 and dc[i] == -1) or
(grid[r][c] != 'D' and dr[i] == 1 and dc[i] == 0) or
(grid[r][c] != 'U' and dr[i] == -1 and dc[i] == 0)):
new_d += 1
direction_change = True
# If the cell is unvisited
if cost[new_r][new_c] > new_d:
cost[new_r][new_c] = new_d
# If the next cell is in the same direction as written in grid[r][c]
if direction_change:
dq.append((new_r, new_c))
# If the next cell is in a different direction as written in grid[r][c]
else:
dq.appendleft((new_r, new_c))
return cost[M - 1][N - 1]
# Test the function
grid = [['R', 'R', 'R', 'R'],
['L', 'L', 'L', 'L'],
['R', 'R', 'R', 'R'],
['L', 'L', 'L', 'L']]
print(min_cost(grid))
Time Complexity: O(M * N), where M is the number of rows and N is the number of columns in the input matrix grid[][]
Auxiliary Space: O(M * N)
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem