Open In App

Minimize the number of turns needed to reach from top left cell to bottom right cell of the matrix.

Last Updated : 28 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a binary 2D matrix maze[][] of size N X N such that a cell (r, c) is blocked if maze[r] = 0 and unblocked if maze[r] = 1, the task is to start from cell (0, 0) to reach (N – 1, N – 1) by minimizing the number of turns. We can take any of the four directions (Up, Left, Right, Down) as the starting direction. Then, from each cell, we can either move forward one cell in the current direction or turn left or right by 90 degrees. Return -1 if it is impossible to reach the cell (N-1, N-1).

Note: We can only travel through the cells which are unblocked.

Examples:

Input: N = 3, maze[][] = {{1, 1}, {1, 1}}
Output: 1
Explanation: We can take the initial direction as right and continue moving till we reach the second column, after which we take a turn and start moving downwards till we reach cell (N-1, N-1).

Input: N = 3, maze[][] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}}
Output: 3
Explanation: Three turns are needed to reach the cell (N-1, N-1) from cell (0, 0)

maze

Approach: The problem can be solved using the following approach:

The problem can be solved using 0-1 BFS. We can take all the four directions (Up, Left, Right and Down) as the initial direction and then start moving in that direction. Now, if we are at any cell (i, j), then the cost of moving to a cell in the same direction is 0 and in any other direction is 1. So, we can use this observation to push all the adjacent cells with cost 0 to the front of the deque and all the other adjacent cells to the back of the deque and minimize the number of turns needed to reach cell (N-1, N-1).

Steps to solve the problem:

  • Initialize a deque dq to store the current cell with its current direction.
  • Create a 2D vector dist[][] to store the minimum number of turns to reach a cell.
  • Push the starting cell (0, 0) and its initial direction (0) to the deque.
  • Pop a cell from the deque.
  • For each valid and unblocked neighbor of the popped cell, check if moving to that neighbor is optimal by checking the dist[][] vector.
  • If moving to the neighbor is optimal, update the minimum number of turns to reach that neighbor and push the neighbor to the front if the neighbor is in the same direction else push it to the back of queue.
  • Return the minimum number of turns to reach the destination cell.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
#define ll long long
#define MOD 1000000007
using namespace std;
 
// Method to check where the cell (r, c) is inside the grid
bool isValid(int r, int c, int N)
{
    return r >= 0 && c >= 0 && r < N && c < N;
}
 
// Method to find the minimum number of turns with given
// initialDirection using 0-1 BFS
int solve(vector<vector<int> >& maze, int initialDirection,
          vector<pair<int, int> > directions, int N)
{
    // Deque to store current cell with current direction
    deque<vector<int> > dq;
    dq.push_back({ 0, 0, initialDirection });
    // 2D vector to store the minimum number of turns to
    // reach a cell
    vector<vector<int> > dist(N, vector<int>(N, 1e9));
    dist[0][0] = 0;
    while (!dq.empty()) {
        vector<int> ele = dq.front();
        dq.pop_front();
        int r = ele[0];
        int c = ele[1];
        int currentDirection = ele[2];
        for (int i = 0; i < 4; i++) {
            int nr = r + directions[i].first,
                nc = c + directions[i].second;
            // Check if the adjacent cell is valid and
            // unblocked
            if (isValid(nr, nc, N) && maze[nr][nc]) {
                int cost = (i == currentDirection ? 0 : 1);
                // Check if moving to this cell is optimal
                // or not
                if (dist[nr][nc] > dist[r] + cost) {
                    dist[nr][nc] = dist[r] + cost;
                    // If the adjacent cell is in the same
                    // direction as the previous one. then
                    // push the cell to the front
                    if (cost == 0) {
                        dq.push_front({ nr, nc, i });
                    }
                    // If the  adjacent cell is not in the
                    // same direction as the previous one,
                    // then push the cell to the back
                    else {
                        dq.push_back({ nr, nc, i });
                    }
                }
            }
        }
    }
    return dist[N - 1][N - 1];
}
 
// Method to find the minimum number of turns
int minimumTurns(int N, vector<vector<int> >& maze)
{
    // vector to move to an adjacent cell
    vector<pair<int, int> > directions{
        { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }
    };
    // Explore all the four directions as initial direction
    int res = min({ solve(maze, 0, directions, N),
                    solve(maze, 1, directions, N),
                    solve(maze, 2, directions, N),
                    solve(maze, 3, directions, N) });
 
    return res == 1e9 ? -1 : res;
}
 
int main()
{
    // Input
    int N = 3;
    vector<vector<int> > maze
        = { { 1, 0, 1 }, { 1, 1, 0 }, { 0, 1, 1 } };
    cout << minimumTurns(N, maze) << "\n";
    return 0;
}


Java




import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
 
public class MinTurns {
 
    // Method to check if the cell (r, c) is inside the grid
    static boolean isValid(int r, int c, int N) {
        return r >= 0 && c >= 0 && r < N && c < N;
    }
 
    // Method to find the minimum number of turns with given
    // initialDirection using 0-1 BFS
    static int solve(int[][] maze, int initialDirection,
                     int[][] directions, int N) {
        // Deque to store the current cell with the current direction
        Deque<int[]> dq = new ArrayDeque<>();
        dq.add(new int[]{0, 0, initialDirection});
 
        // 2D array to store the minimum number of turns to reach a cell
        int[][] dist = new int[N][N];
        for (int[] row : dist) {
            Arrays.fill(row, Integer.MAX_VALUE);
        }
        dist[0][0] = 0;
 
        while (!dq.isEmpty()) {
            int[] ele = dq.pollFirst();
            int r = ele[0];
            int c = ele[1];
            int currentDirection = ele[2];
 
            for (int i = 0; i < 4; i++) {
                int nr = r + directions[i][0];
                int nc = c + directions[i][1];
 
                // Check if the adjacent cell is valid and unblocked
                if (isValid(nr, nc, N) && maze[nr][nc] == 1) {
                    int cost = (i == currentDirection ? 0 : 1);
 
                    // Check if moving to this cell is optimal or not
                    if (dist[nr][nc] > dist[r] + cost) {
                        dist[nr][nc] = dist[r] + cost;
 
                        // If the adjacent cell is in the same direction as the previous one,
                        // then push the cell to the front
                        if (cost == 0) {
                            dq.addFirst(new int[]{nr, nc, i});
                        }
                        // If the adjacent cell is not in the same direction as the previous one,
                        // then push the cell to the back
                        else {
                            dq.addLast(new int[]{nr, nc, i});
                        }
                    }
                }
            }
        }
 
        return dist[N - 1][N - 1];
    }
 
    // Method to find the minimum number of turns
    static int minimumTurns(int N, int[][] maze) {
        // Array to move to an adjacent cell
        int[][] directions = {
                {0, 1}, {1, 0}, {0, -1}, {-1, 0}
        };
 
        // Explore all four directions as the initial direction
        int res = Math.min(Math.min(
                solve(maze, 0, directions, N),
                solve(maze, 1, directions, N)),
                Math.min(
                        solve(maze, 2, directions, N),
                        solve(maze, 3, directions, N)
                )
        );
 
        return res == Integer.MAX_VALUE ? -1 : res;
    }
 
    public static void main(String[] args) {
        // Input
        int N = 3;
        int[][] maze = {
                {1, 0, 1},
                {1, 1, 0},
                {0, 1, 1}
        };
 
        System.out.println(minimumTurns(N, maze));
    }
}
 
// This code is contributed by shivamgupta0987654321


Python3




from collections import deque
 
# Method to check if the cell (r, c) is inside the grid
def is_valid(r, c, N):
    return 0 <= r < N and 0 <= c < N
 
# Method to find the minimum number of turns with given
# initialDirection using 0-1 BFS
def solve(maze, initial_direction, directions, N):
    # Deque to store the current cell with the current direction
    dq = deque([(0, 0, initial_direction)])
    # 2D list to store the minimum number of turns to reach a cell
    dist = [[float('inf')] * N for _ in range(N)]
    dist[0][0] = 0
 
    while dq:
        r, c, current_direction = dq.popleft()
        for i in range(4):
            nr, nc = r + directions[i][0], c + directions[i][1]
            # Check if the adjacent cell is valid and unblocked
            if is_valid(nr, nc, N) and maze[nr][nc]:
                cost = 0 if i == current_direction else 1
                # Check if moving to this cell is optimal or not
                if dist[nr][nc] > dist[r] + cost:
                    dist[nr][nc] = dist[r] + cost
                    # If the adjacent cell is in the same
                    # direction as the previous one, then
                    # append the cell to the left
                    if cost == 0:
                        dq.appendleft((nr, nc, i))
                    # If the adjacent cell is not in the
                    # same direction as the previous one,
                    # then append the cell to the right
                    else:
                        dq.append((nr, nc, i))
 
    return dist[N-1][N-1]
 
# Method to find the minimum number of turns
def minimum_turns(N, maze):
    # List to move to an adjacent cell
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    # Explore all four directions as the initial direction
    res = min(solve(maze, i, directions, N) for i in range(4))
 
    return -1 if res == float('inf') else res
 
if __name__ == "__main__":
    # Input
    N = 3
    maze = [
        [1, 0, 1],
        [1, 1, 0],
        [0, 1, 1]
    ]
    print(minimum_turns(N, maze))


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    // Method to check if cell (r, c) is inside the grid
    static bool IsValid(int r, int c, int N)
    {
        return r >= 0 && c >= 0 && r < N && c < N;
    }
 
    // Method to find the minimum number of turns with given initialDirection using 0-1 BFS
    static int Solve(List<List<int>> maze, int initialDirection, List<Tuple<int, int>> directions, int N)
    {
        Queue<List<int>> dq = new Queue<List<int>>();
        dq.Enqueue(new List<int> { 0, 0, initialDirection });
 
        int[,] dist = new int[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                dist[i, j] = int.MaxValue;
            }
        }
 
        dist[0, 0] = 0;
 
        while (dq.Count > 0)
        {
            List<int> ele = dq.Dequeue();
            int r = ele[0];
            int c = ele[1];
            int currentDirection = ele[2];
 
            for (int i = 0; i < 4; i++)
            {
                int nr = r + directions[i].Item1;
                int nc = c + directions[i].Item2;
 
                if (IsValid(nr, nc, N) && maze[nr][nc] == 1)
                {
                    int cost = (i == currentDirection) ? 0 : 1;
 
                    if (dist[nr, nc] > dist[r, c] + cost)
                    {
                        dist[nr, nc] = dist[r, c] + cost;
                        if (cost == 0)
                        {
                            dq.Enqueue(new List<int> { nr, nc, i });
                        }
                        else
                        {
                            dq.Enqueue(new List<int> { nr, nc, i });
                        }
                    }
                }
            }
        }
 
        return dist[N - 1, N - 1];
    }
 
    // Method to find the minimum number of turns
    static int MinimumTurns(int N, List<List<int>> maze)
    {
        List<Tuple<int, int>> directions = new List<Tuple<int, int>>
        {
            Tuple.Create(0, 1), Tuple.Create(1, 0), Tuple.Create(0, -1), Tuple.Create(-1, 0)
        };
 
        int res = new int[]
        {
            Solve(maze, 0, directions, N),
            Solve(maze, 1, directions, N),
            Solve(maze, 2, directions, N),
            Solve(maze, 3, directions, N)
        }.Min();
 
        return res == int.MaxValue ? -1 : res;
    }
 
    static void Main()
    {
        // Input
        int N = 3;
        List<List<int>> maze = new List<List<int>>
        {
            new List<int> { 1, 0, 1 },
            new List<int> { 1, 1, 0 },
            new List<int> { 0, 1, 1 }
        };
 
        Console.WriteLine(MinimumTurns(N, maze));
    }
}
 
// This code is contributed by shivamgupta0987654321


Javascript




// JavaScript Implementation of the given problem
 
// Method to check if the cell (r, c)
// is inside the grid
function isValid(r, c, N) {
    return r >= 0 && c >= 0 && r < N && c < N;
}
 
// Method to find the minimum number of
// turns with given initialDirection using 0-1 BFS
function solve(maze, initialDirection, directions, N) {
    // Deque to store current cell
    // with current direction
    let dq = [[0, 0, initialDirection]];
    // 2D array to store minimum number
    // of turns to reach a cell
    let dist = new Array(N).fill(null).map(() => new Array(N).fill(1e9));
     
    dist[0][0] = 0;
 
    while (dq.length > 0) {
        let [r, c, currentDirection] = dq.shift();
 
        for (let i = 0; i < 4; i++) {
            let nr = r + directions[i][0];
            let nc = c + directions[i][1];
 
            // Check if the adjacent cell is valid and unblocked
            if (isValid(nr, nc, N) && maze[nr][nc]) {
                let cost = (i === currentDirection ? 0 : 1);
 
                // Check if moving to this cell is optimal or not
                if (dist[nr][nc] > dist[r] + cost) {
                    dist[nr][nc] = dist[r] + cost;
 
                    // If the adjacent cell is in the
                    // same direction as the previous one,
                    // then push the cell to the front
                    if (cost === 0) {
                        dq.unshift([nr, nc, i]);
                    }
                    else {
                        // If the adjacent cell is not
                        // in the same direction as the previous
                        // one, then push the cell to the back
                        dq.push([nr, nc, i]);
                    }
                }
            }
        }
    }
    return dist[N - 1][N - 1];
}
 
// Method to find the minimum number of turns
function minimumTurns(N, maze) {
    let directions = [
        [0, 1], [1, 0], [0, -1], [-1, 0]
    ]; // Vector to move to an adjacent cell
 
    // Explore all the four directions as initial direction
    let res = Math.min(
        solve(maze, 0, directions, N),
        solve(maze, 1, directions, N),
        solve(maze, 2, directions, N),
        solve(maze, 3, directions, N)
    );
 
    return res === 1e9 ? -1 : res;
}
 
// Input
let N = 3;
let maze = [
    [1, 0, 1],
    [1, 1, 0],
    [0, 1, 1]
];
 
console.log(minimumTurns(N, maze));


Output

3








Time Complexity: O(4 * N * N), where N is the number of rows or columns in the grid.
Auxiliary Space: O(N * N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads