Open In App

Shortest path by removing K walls

Last Updated : 23 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a 2D binary matrix of size N * M, where 0 represents an empty space while 1 represents a wall you cannot walk through. You are also given an integer K. You can walk up, down, left, or right. Given that you can remove up to K walls, return the minimum number of steps to walk from the top left corner (0, 0) to the bottom right corner (N-1, M-1). 

Note: If there is no way to walk from the top left corner to the bottom right corner, return -1.

Examples:

Input: N = 3, M = 3, K = 1
mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}}
Output: 4
Explanation: We can remove any one of the walls and reach the bottom in 4 moves.

The below image gives the paths through which we can go from the source to the destination.

Image showing most of the paths from the source to the destination

If we carefully observe the paths shown above then, we will see that in these paths we have one cell that contains 1 and since we have k=1 hence we can traverse this cell also, and hence it gives the minimum steps.

Input: N = 2, M = 2, K = 0
mat[] = {{0, 1}, {1, 0}}
Output: -1
Explanation: There’s no way of reaching the bottom corner without removing any walls.

Approach:

The idea is to use breadth first search to calculate the shortest path from source to destination.

Follow the steps below to solve the problem:

  • Initialize a 3D array that ensures that we don’t visit the same cell again and again. Also,Initialize the steps as 0.
  • Initialize a queue data structure that contains a list that will be composed of the current_X coordinate, current_Y coordinate, and the no. of obstacles that we can destroy. Push the current cell into the queue.
  • Do the following until the queue becomes empty:- 
    • Pop the front element from the queue and explore this popped cell in all four directions such that the current_X coordinate and current_Y coordinate should not cross the boundary.
    • If the current cell is 0 and not visited then explore all the directions. Push all the nonvisited cells from this cell into the queue. Mark this cell as visited. 
    • If the current cell is 1 which means it represents a wall and this cell is not visited as well as the no of obstacles that we can destroy is greater than 1 which means that we can destroy this wall and then explore all the directions. Push all the nonvisited cells from this cell into the queue. Mark this cell as visited. 
    • After each iteration increment the step value. 
    • During the previous two steps, if at any time the current_X coordinate, current_Y coordinate is equal to the destination_X coordinate, destination_Y coordinate then return the steps.

Below is the implementation of the above approach. 

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the minimum number of steps
int shortestPath(vector<vector<int> > mat, int k)
{
    int n = mat.size();
    int m = mat[0].size();
    if (n == 1 && m == 1 && (mat[0][0] == 0 || k >= 1))
        return 0;
 
    vector<vector<vector<bool> > > visited(
        n, vector<vector<bool> >(
               m, vector<bool>(k + 1, false)));
    int steps = 0;
 
    queue<vector<int> > q;
    q.push({ 0, 0, k });
    int ar1[4] = { 1, -1, 0, 0 };
    int ar2[4] = { 0, 0, -1, 1 };
 
    // Loop to run a BFS
    while (!q.empty()) {
        int size = q.size();
 
        steps++;
        while (size--) {
            auto curr = q.front();
            int i = curr[0], j = curr[1], w = curr[2];
            q.pop();
            visited[i][j][w] = true;
            for (int dir = 0; dir < 4; dir++) {
                int new_x = i + ar1[dir];
                int new_y = j + ar2[dir];
                int new_k = w;
                if (new_x >= 0 && new_x < n && new_y >= 0
                    && new_y < m) {
                    if (mat[new_x][new_y] == 0
                        && !visited[new_x][new_y][new_k]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.push({ new_x, new_y, new_k });
                        visited[new_x][new_y][new_k] = true;
                    }
                    else if (mat[new_x][new_y] == 1
                             && new_k >= 1
                             && !visited[new_x][new_y]
                                        [new_k - 1]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.push({ new_x, new_y, new_k - 1 });
                        visited[new_x][new_y][new_k - 1]
                            = true;
                    }
                }
            }
        }
    }
    return -1;
}
 
// Driver code
int main()
{
    vector<vector<int> > mat
        = { { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 } };
    int K = 1;
 
    // Function call
    cout << shortestPath(mat, K);
    return 0;
}


Java




// Java code to implement the approach
 
import java.io.*;
import java.util.*;
 
class GFG {
     
    // Function to find the minimum number of steps
public static int shortestPath(int[][] mat, int k)
{
    int n = mat.length;
    int m = mat[0].length;
    if (n == 1 && m == 1 && (mat[0][0] == 0 || k >= 1))
        return 0;
 
    boolean[][][] visited = new boolean [n][m][k+1];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            for(int q=0;q<k+1;q++)
            {
                visited[i][j][q]=false;
            }
        }
    }
     
    int steps = 0;
 
    ArrayList<ArrayList<Integer> > q
            = new ArrayList<ArrayList<Integer> >();
     
    q.add(new ArrayList<Integer>(Arrays.asList(0, 0, k)));
    int[] ar1 = { 1, -1, 0, 0 };
    int[] ar2 = { 0, 0, -1, 1 };
 
    // Loop to run a BFS
    while (q.size()!=0) {
        int size = q.size();
 
        steps++;
        while (size>0) {
            ArrayList<Integer> curr = q.get(0);
            int i = curr.get(0), j = curr.get(1), w = curr.get(2);
            q.remove(0);
            visited[i][j][w] = true;
            for (int dir = 0; dir < 4; dir++) {
                int new_x = i + ar1[dir];
                int new_y = j + ar2[dir];
                int new_k = w;
                if (new_x >= 0 && new_x < n && new_y >= 0
                    && new_y < m) {
                    if (mat[new_x][new_y] == 0
                        && !visited[new_x][new_y][new_k]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.add(new ArrayList<Integer>(Arrays.asList(new_x,new_y,new_k)));
                        visited[new_x][new_y][new_k] = true;
                    }
                    else if (mat[new_x][new_y] == 1
                            && new_k >= 1
                            && !visited[new_x][new_y]
                                        [new_k - 1]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.add(new ArrayList<Integer>(Arrays.asList(new_x,new_y,new_k-1)));
                        visited[new_x][new_y][new_k - 1]
                            = true;
                    }
                }
            }
            size--;
        }
    }
    return -1;
}
 
    public static void main (String[] args) {
        int[][] mat
        = { { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 } };
    int K = 1;
 
    // Function call
    System.out.println(shortestPath(mat, K));
    }
}
 
// This code is contributed by Aman Kumar


Python3




# Python3 code to implement the approach
 
# Function to find the minimum number of steps
def shortestPath(mat, k):
 
    n = len(mat)
    m = len(mat[0])
    if (n == 1 and m == 1 and (mat[0][0] == 0 or k >= 1)):
        return 0
 
    visited = [[[False for _ in range(k+1)]
                for _ in range(m)] for _ in range(n)]
    steps = 0
 
    q = []
    q.append([0, 0, k])
 
    ar1 = [1, -1, 0, 0]
    ar2 = [0, 0, -1, 1]
 
    # Loop to run a BFS
    while (len(q) != 0):
        size = len(q)
 
        steps += 1
        while (size):
            curr = q.pop(0)
            i = curr[0]
            j = curr[1]
            w = curr[2]
 
            visited[i][j][w] = True
            for dir in range(0, 4):
                new_x = i + ar1[dir]
                new_y = j + ar2[dir]
                new_k = w
                if (new_x >= 0 and new_x < n and new_y >= 0
                        and new_y < m):
                    if (mat[new_x][new_y] == 0
                            and (not visited[new_x][new_y][new_k])):
                        if (new_x == n - 1
                                and new_y == m - 1):
                            return steps
                        q.append([new_x, new_y, new_k])
                        visited[new_x][new_y][new_k] = True
 
                    elif (mat[new_x][new_y] == 1
                          and new_k >= 1
                          and (not visited[new_x][new_y]
                               [new_k - 1])):
                        if (new_x == n - 1
                                and new_y == m - 1):
                            return steps
                        q.append([new_x, new_y, new_k - 1])
                        visited[new_x][new_y][new_k - 1] = True
            size -= 1
    return -1
 
# Driver code
if __name__ == "__main__":
 
    mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
    K = 1
 
    # Function call
    print(shortestPath(mat, K))
 
    # This code is contributed by rakeshsahni


C#




// C# Code to implement the approach
using System;
using System.Collections.Generic;
public class Program
{
   
  // Function to find the minimum number of steps
  public static int ShortestPath(int[, ] mat, int k)
  {
    int n = mat.GetLength(0);
    int m = mat.GetLength(1);
    if (n == 1 && m == 1 && (mat[0, 0] == 0 || k >= 1))
      return 0;
    bool[, , ] visited = new bool[n, m, k + 1];
    int steps = 0;
    Queue<int[]> q = new Queue<int[]>();
    q.Enqueue(new int[] { 0, 0, k });
    int[] ar1 = { 1, -1, 0, 0 };
    int[] ar2 = { 0, 0, -1, 1 };
    // Loop to run a BFS
    while (q.Count != 0) {
      int size = q.Count;
      steps++;
      while (size-- > 0) {
        int[] curr = q.Dequeue();
        int i = curr[0], j = curr[1], w = curr[2];
        visited[i, j, w] = true;
        for (int dir = 0; dir < 4; dir++) {
          int new_x = i + ar1[dir];
          int new_y = j + ar2[dir];
          int new_k = w;
          if (new_x >= 0 && new_x < n
              && new_y >= 0 && new_y < m) {
            if (mat[new_x, new_y] == 0
                && !visited[new_x, new_y,
                            new_k]) {
              if (new_x == n - 1
                  && new_y == m - 1)
                return steps;
              q.Enqueue(new int[] {
                new_x, new_y, new_k });
              visited[new_x, new_y, new_k]
                = true;
            }
            else if (mat[new_x, new_y] == 1
                     && new_k >= 1
                     && !visited[new_x, new_y,
                                 new_k - 1]) {
              if (new_x == n - 1
                  && new_y == m - 1)
                return steps;
              q.Enqueue(new int[] {
                new_x, new_y, new_k - 1 });
              visited[new_x, new_y, new_k - 1]
                = true;
            }
          }
        }
      }
    }
    return -1;
  }
   
  // Driver Code
  public static void Main()
  {
    int[, ] mat
      = { { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 } };
    int K = 1;
     
    // Function call
    Console.WriteLine(ShortestPath(mat, K));
  }
}
 
// This code is contributed by ishankhandelwals.


Javascript




// JavaScript code to implement the approach
function shotestPath(mat, k) {
    let n = mat.length;
    let m = mat[0].length;
    if (n == 1 && m == 1 && (mat[0][0] == 0 || k >= 1))
        return 0;
    let visited = Array(n).fill().map(() => Array(m).fill().map(() => Array(k + 1).fill(false)));
    let steps = 0;
    let q = [];
    q.push([0, 0, k]);
    let ar1 = [1, -1, 0, 0];
    let ar2 = [0, 0, -1, 1];
     
    // Loop to run a BFS
    while (q.length > 0) {
        let size = q.length;
        steps++;
        while (size-- > 0) {
            let curr = q.shift();
            let i = curr[0], j = curr[1], w = curr[2];
            visited[i][j][w] = true;
            for (let dir = 0; dir < 4; dir++) {
                let new_x = i + ar1[dir];
                let new_y = j + ar2[dir];
                let new_k = w;
                if (new_x >= 0 && new_x < n && new_y >= 0
                    && new_y < m) {
                    if (mat[new_x][new_y] == 0
                        && !visited[new_x][new_y][new_k]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.push([new_x, new_y, new_k]);
                        visited[new_x][new_y][new_k] = true;
                    }
                    else if (mat[new_x][new_y] == 1
                        && new_k >= 1
                        && !visited[new_x][new_y]
                        [new_k - 1]) {
                        if (new_x == n - 1
                            && new_y == m - 1)
                            return steps;
                        q.push([new_x, new_y, new_k - 1]);
                        visited[new_x][new_y][new_k - 1]
                            = true;
                    }
                }
            }
        }
    }
    return -1;
}
 
// Driver code
let mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]];
let K = 1;
 
// Function call
console.log(shortestPath(mat, K));
 
// This code is contributed by ishankhandelwals.


Output

4

Time Complexity: O(N*M*K), For every cell (M*N), in the worst case we have to put that cell into the queue K times.
Space Complexity: O(N*M*K), In the worst case store all of those steps/paths in the visited set.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads