Open In App

Minimum cost to reach the last cell of a grid with directions

Last Updated : 05 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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.

MinimumCostPath

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], 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];
                bool directionChange = false;
                // If the next cell is in a different
                // direction
                if ((grid[r] != 'R' && dr[i] == 0 &&
                     dc[i] == 1) ||
                    (grid[r] != 'L' && dr[i] == 0 &&
                     dc[i] == -1) ||
                    (grid[r] != 'D' && dr[i] == 1 &&
                     dc[i] == 0) ||
                    (grid[r] != '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]
                    if (directionChange)
                    {
                        dq.push_back({new_r, new_c});
                    }
                    // If the next cell is in a different
                    // direction as written in grid[r]
                    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];
                    boolean directionChange = false;
 
                    // If the next cell is in a different direction
                    if ((grid[r] != 'R' && dr[i] == 0 && dc[i] == 1)
                            || (grid[r] != 'L' && dr[i] == 0 && dc[i] == -1)
                            || (grid[r] != 'D' && dr[i] == 1 && dc[i] == 0)
                            || (grid[r] != '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]
                        if (directionChange) {
                            dq.addLast(new int[]{new_r, new_c});
                        }
                        // If the next cell is in a different
                        // direction as written in grid[r]
                        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];
                    bool directionChange = false;
                    // If the next cell is in a different
                    // direction
                    if ((grid[r] != 'R' && dr[i] == 0 &&
                         dc[i] == 1) ||
                        (grid[r] != 'L' && dr[i] == 0 &&
                         dc[i] == -1) ||
                        (grid[r] != 'D' && dr[i] == 1 &&
                         dc[i] == 0) ||
                        (grid[r] != '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]
                        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]
                        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];
                let directionChange = false;
 
                // If the next cell is in a different direction
                if (
                    (grid[r] !== 'R' && dr[i] === 0 && dc[i] === 1) ||
                    (grid[r] !== 'L' && dr[i] === 0 && dc[i] === -1) ||
                    (grid[r] !== 'D' && dr[i] === 1 && dc[i] === 0) ||
                    (grid[r] !== '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]
                direction_change = False
                # If the next cell is in a different direction
                if ((grid[r] != 'R' and dr[i] == 0 and dc[i] == 1) or
                    (grid[r] != 'L' and dr[i] == 0 and dc[i] == -1) or
                    (grid[r] != 'D' and dr[i] == 1 and dc[i] == 0) or
                    (grid[r] != '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]
                    if direction_change:
                        dq.append((new_r, new_c))
                    # If the next cell is in a different direction as written in grid[r]
                    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))


Output

3






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)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads