Open In App

Shortest Path to Get Food in Matrix

Last Updated : 18 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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));

Output
3

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)




Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads