Shortest Path to Get Food in Matrix
Last Updated : 18 Apr, 2024
Given a matrix grid[][], where '*' represents your location, '#' represents food cells, 'O' represents free space, 'X' represents obstacles. The task is to find the shortest path from your location to any food cell in a given matrix grid, Return the length of the shortest path to reach any food cell, or -1 if no path exists.
Example:
Input: grid = [["X","X","X","X","X","X"],["X","*","O","O","O","X"],["X","O","O","#","O","X"],["X","X","X","X","X","X"]]
Output: 3
Explanation: only 3 steps needed o reach the food.
Input: grid = [["X","X","X","X","X"],["X","*","X","O","X"],["X","O","X","#","X"],["X","X","X","X","X"]]
Output: -1
Explanation: Not possible to reach the food.
Approach:
The idea is to use multi-source Breadth-First Search (BFS) algorithm. Starts the BFS from the given location and explores the neighbor nodes at the present depth prior to moving on to nodes at the next depth level.
This property of BFS is useful in this problem because it guarantees that we explore all cells at a given distance before moving on to the cells at the next distance. Therefore, the first time we reach a food cell, we can be sure that we have found the shortest path.
Steps-by-step approach:
- Initialize a queue (Q) to keep track of cells to visit.
- Map grid values ('*', '#', 'O') to integers (1, 2, 3) for better handling.
- Find the starting points marked by '*' and add it to the queue.
- Perform a Breadth-First Search (BFS) traversal of the grid using the queue.
- For each cell popped from the queue:
- If it's a food cell ('#'), update the shortest path length and exit the BFS loop.
- If it's an empty space ('O'), mark it as visited and continue exploring neighboring cells.
- Use a priority queue to ensure food cells are explored first.
- At the end of BFS, return the length of the shortest path to reach any food cell. If no path exists, return -1.
Below are the implementation of the above approach:
C++ #include <bits/stdc++.h> using namespace std; // Function to find the shortest path from your location to // any food cell int findShortestPathToFood(vector<vector<char> >& grid) { // Initialize a queue to keep track of cells to visit queue<vector<int> > Q; // <value, distance, x, y> /* we mapped grid value to integer: '*': 1 '#': 2 'O': 3 */ // Define the four possible directions to move in the // grid vector<vector<int> > directions = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }; // Get the size of the grid int numRows = grid.size(), numCols = grid[0].size(); // Find your location in the grid and add it to the // queue for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { if (grid[row][col] == '*') { Q.push({ 1, 0, row, col }); } } } // Initialize the result to -1 (no path found) int shortestPathLength = -1; // Create a visited matrix to keep track of visited // cells vector<vector<int> > visited(numRows, vector<int>(numCols)); // Start BFS while (!Q.empty()) { auto currentCell = Q.front(); Q.pop(); // If we have reached a food cell, update the // shortest path length and break if (currentCell[0] == 2) { shortestPathLength = currentCell[1]; break; } // Visit all adjacent cells for (int i = 0; i < 4; i++) { int newRow = directions[i][0] + currentCell[2]; int newCol = directions[i][1] + currentCell[3]; // If the new cell is within the grid, not an // obstacle, and not visited if (newRow >= 0 && newRow < numRows && newCol >= 0 && newCol < numCols && (grid[newRow][newCol] == 'O' || grid[newRow][newCol] == '#') && visited[newRow][newCol] == 0) { // Mark the new cell as visited visited[newRow][newCol] = 1; // If the new cell is a food cell, add it to // the queue with a priority of 2 if (grid[newRow][newCol] == '#') { Q.push({ 2, currentCell[1] + 1, newRow, newCol }); } // If the new cell is a free space, add it // to the queue with a priority of 3 else { Q.push({ 3, currentCell[1] + 1, newRow, newCol }); } } } } // Return the length of the shortest path to reach any // food cell, or -1 if no path exists return shortestPathLength; } int main() { vector<vector<char> > grid = { { 'X', 'X', 'X', 'X', 'X', 'X' }, { 'X', '*', 'O', 'O', 'O', 'X' }, { 'X', 'O', 'O', '#', 'O', 'X' }, { 'X', 'X', 'X', 'X', 'X', 'X' } }; cout << findShortestPathToFood(grid); return 0; } Java import java.util.LinkedList; import java.util.Queue; public class GFG { // Function to find the shortest path from your location to // any food cell public static int findShortestPathToFood(char[][] grid) { // Initialize a queue to keep track of cells to visit Queue<int[]> queue = new LinkedList<>(); // <value, distance, x, y> /* we mapped grid value to integer: '*': 1 '#': 2 'O': 3 */ // Define the four possible directions to move in the // grid int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; // Get the size of the grid int numRows = grid.length; int numCols = grid[0].length; // Find your location in the grid and add it to the // queue for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { if (grid[row][col] == '*') { queue.add(new int[]{1, 0, row, col}); } } } // Initialize the result to -1 (no path found) int shortestPathLength = -1; // Create a visited matrix to keep track of visited // cells boolean[][] visited = new boolean[numRows][numCols]; // Start BFS while (!queue.isEmpty()) { int[] currentCell = queue.poll(); // If we have reached a food cell, update the // shortest path length and break if (currentCell[0] == 2) { shortestPathLength = currentCell[1]; break; } // Visit all adjacent cells for (int[] direction : directions) { int newRow = direction[0] + currentCell[2]; int newCol = direction[1] + currentCell[3]; // If the new cell is within the grid, not an // obstacle, and not visited if (newRow >= 0 && newRow < numRows && newCol >= 0 && newCol < numCols && (grid[newRow][newCol] == 'O' || grid[newRow][newCol] == '#') && !visited[newRow][newCol]) { // Mark the new cell as visited visited[newRow][newCol] = true; // If the new cell is a food cell, add it to // the queue with a priority of 2 if (grid[newRow][newCol] == '#') { queue.add(new int[]{2, currentCell[1] + 1, newRow, newCol}); } // If the new cell is a free space, add it // to the queue with a priority of 3 else { queue.add(new int[]{3, currentCell[1] + 1, newRow, newCol}); } } } } // Return the length of the shortest path to reach any // food cell, or -1 if no path exists return shortestPathLength; } public static void main(String[] args) { char[][] grid = { {'X', 'X', 'X', 'X', 'X', 'X'}, {'X', '*', 'O', 'O', 'O', 'X'}, {'X', 'O', 'O', '#', 'O', 'X'}, {'X', 'X', 'X', 'X', 'X', 'X'} }; System.out.println(findShortestPathToFood(grid)); } } Python3 from collections import deque # Function to find the shortest path from your location to any food cell def findShortestPathToFood(grid): # Define the four possible directions to move in the grid directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] # Get the size of the grid numRows, numCols = len(grid), len(grid[0]) # Initialize a queue to keep track of cells to visit Q = deque() # (value, distance, x, y) # Find your location in the grid and add it to the queue for row in range(numRows): for col in range(numCols): if grid[row][col] == '*': Q.append((1, 0, row, col)) # Initialize the result to -1 (no path found) shortestPathLength = -1 # Create a visited matrix to keep track of visited cells visited = [[0] * numCols for _ in range(numRows)] # Start BFS while Q: currentCell = Q.popleft() # If we have reached a food cell, update the shortest path length and break if currentCell[0] == 2: shortestPathLength = currentCell[1] break # Visit all adjacent cells for direction in directions: newRow, newCol = direction[0] + currentCell[2], direction[1] + currentCell[3] # If the new cell is within the grid, not an obstacle, and not visited if 0 <= newRow < numRows and 0 <= newCol < numCols and (grid[newRow][newCol] == 'O' or grid[newRow][newCol] == '#') and not visited[newRow][newCol]: # Mark the new cell as visited visited[newRow][newCol] = 1 # If the new cell is a food cell, add it to the queue with a priority of 2 if grid[newRow][newCol] == '#': Q.append((2, currentCell[1] + 1, newRow, newCol)) # If the new cell is a free space, add it to the queue with a priority of 3 else: Q.append((3, currentCell[1] + 1, newRow, newCol)) # Return the length of the shortest path to reach any food cell, or -1 if no path exists return shortestPathLength # Driver code if __name__ == "__main__": grid = [ ['X', 'X', 'X', 'X', 'X', 'X'], ['X', '*', 'O', 'O', 'O', 'X'], ['X', 'O', 'O', '#', 'O', 'X'], ['X', 'X', 'X', 'X', 'X', 'X'] ] print(findShortestPathToFood(grid))
JavaScript // Function to find the shortest path from your location to any food cell function findShortestPathToFood(grid) { // Initialize a queue to keep track of cells to visit const queue = []; // [value, distance, x, y] /* We mapped grid value to integer: '*': 1 '#': 2 'O': 3 */ // Define the four possible directions to move in the grid const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; // Get the size of the grid const numRows = grid.length; const numCols = grid[0].length; // Find your location in the grid and add it to the queue for (let row = 0; row < numRows; row++) { for (let col = 0; col < numCols; col++) { if (grid[row][col] === '*') { queue.push([1, 0, row, col]); } } } // Initialize the result to -1 (no path found) let shortestPathLength = -1; // Create a visited matrix to keep track of visited cells const visited = new Array(numRows).fill(null).map(() => new Array(numCols).fill(false)); // Start BFS while (queue.length) { const currentCell = queue.shift(); // If we have reached a food cell, update the shortest path length and break if (currentCell[0] === 2) { shortestPathLength = currentCell[1]; break; } // Visit all adjacent cells for (const direction of directions) { const newRow = direction[0] + currentCell[2]; const newCol = direction[1] + currentCell[3]; // If the new cell is within the grid, not an obstacle, and not visited if (newRow >= 0 && newRow < numRows && newCol >= 0 && newCol < numCols && (grid[newRow][newCol] === 'O' || grid[newRow][newCol] === '#') && !visited[newRow][newCol]) { // Mark the new cell as visited visited[newRow][newCol] = true; // If the new cell is a food cell, add it to the queue with a priority of 2 if (grid[newRow][newCol] === '#') { queue.push([2, currentCell[1] + 1, newRow, newCol]); } // If the new cell is a free space, add it to the queue with a priority of 3 else { queue.push([3, currentCell[1] + 1, newRow, newCol]); } } } } // Return the length of the shortest path to reach any food cell, or -1 if no path exists return shortestPathLength; } // Driver code const grid = [ ['X', 'X', 'X', 'X', 'X', 'X'], ['X', '*', 'O', 'O', 'O', 'X'], ['X', 'O', 'O', '#', 'O', 'X'], ['X', 'X', 'X', 'X', 'X', 'X'] ]; console.log(findShortestPathToFood(grid)); Time complexity: O(N*M), where N and M are the number of rows and columns in the given matrix
Auxiliary Space: O(N*M)
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem
My Profile