Horje
CSES Solutions – Labyrinth

You are given a map of a labyrinth, and your task is to find a path from start to end. You can walk left, right, up and down.

The first input line has two integers n and m: the height and width of the map. Then there are lines of m characters describing the labyrinth. Each character is . (floor), # (wall), A (start), or B (end). There is exactly one A and one B in the input.

Examples:

Input: n = 5, m = 8, labyrinth = {“########”, “#.A#…#”, “#.##.#B#”, “#……#”, “########” }
Output:
YES
9
LDDRRRRRU
Explanation: The shortest path has 9 moves: Left, Down, Down, Right, Right, Right, Right, Right, Up.

Input: n = 10, m = 10, labyrinth = {“##.A######”, “#.##.##.##”, “#####..###”, “.#########”, “.########.”, “###.###.##”, “#########.”, “######.#.#”, “###..###.#”, “###.B#####”}
Output: NO

Approach:

To find the path from the start to end in the labyrinth we can use a breadth-first search (BFS) algorithm. We start BFS from the starting point (‘A’) and explore all possible directions (left, right, up, down) until we reach the end point (‘B’). We keep track of the shortest path length and path itself during BFS traversal. Also, keep a track of the direction from which we have visited the current cell. For example: if we have visited the current cell by moving down from the cell above, then we store ‘D’ in steps[][].

Step-by-step algorithm:

  • Read the dimensions of the grid and initialize the grid with the static input.
  • Find the starting and ending positions in the grid.
  • Implement a BFS (Breadth-First Search) algorithm to the find the shortest path from the starting point to the ending point.
  • If the ending point is reachable reconstruct the path using a parent array to the store the direction of the movement at each cell.
  • Output “YES” followed by the minimum number of the steps required to reach the ending point and sequence of movements to the reach there. If the ending point is not reachable output “NO”.

Below is the implementation of the algorithm:

C++
#include <bits/stdc++.h>
#define ll long long int
using namespace std;

vector<string> graph(1000);
vector<vector<char> > steps(1000, vector<char>(1000));
bool visited[1000][1000];
pair<ll, ll> start, dest;
stack<char> ans;
ll n, m;

// function to check whether the current cell is unvisited,
// unblocked and inside the grid
bool is_valid(ll x, ll y)
{
    return (x >= 0 && x < n && y >= 0 && y < m
            && graph[x][y] != '#'
            && visited[x][y] == false);
}

// Function to backtrack and extract the path from B to A
void backtrack(ll x, ll y)
{
    if (steps[x][y] != 'X') {
        char ch = steps[x][y];
        ans.push(ch);
        // Move one cell up
        if (ch == 'U')
            backtrack(x + 1, y);
        // Move one cell down
        else if (ch == 'D')
            backtrack(x - 1, y);
        // Move one cell left
        else if (ch == 'L')
            backtrack(x, y + 1);
        // Move one cell right
        else if (ch == 'R')
            backtrack(x, y - 1);
    }
}

// function to run bfs and find the shortest path from A to
// B
bool bfs(ll x, ll y)
{
    steps[x][y] = 'X';
    bool flag = false;
    // queue to run bfs across the grid
    queue<pair<ll, ll> > q;
    q.push({ x, y });
    while (!q.empty()) {
        pair<ll, ll> ele = q.front();
        x = ele.first;
        y = ele.second;
        q.pop();
        // If we have reached the destination
        if (graph[x][y] == 'B') {
            flag = true;
            break;
        }
        visited[x][y] = true;
        // Move Up
        if (is_valid(x - 1, y)) {
            visited[x - 1][y] = true;
            steps[x - 1][y] = 'U';
            q.push({ x - 1, y });
        }
        // Move Right
        if (is_valid(x, y + 1)) {
            visited[x][y + 1] = true;
            steps[x][y + 1] = 'R';
            q.push({ x, y + 1 });
        }
        // Move Down
        if (is_valid(x + 1, y)) {
            visited[x + 1][y] = true;
            steps[x + 1][y] = 'D';
            q.push({ x + 1, y });
        }
        // Move Left
        if (is_valid(x, y - 1)) {
            visited[x][y - 1] = true;
            steps[x][y - 1] = 'L';
            q.push({ x, y - 1 });
        }
    }
    // If there is a path from A to B, print the path
    if (flag) {
        backtrack(x, y);
        return true;
    }
    else
        return false;
}
int main()
{
    // Sample Input
    n = 5, m = 8;
    graph = { "########", "#.A#...#", "#.##.#B#",
              "#......#", "########" };
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (graph[i][j] == 'A')
                start = { i, j };
            else if (graph[i][j] == 'B')
                dest = { i, j };
        }
    }
    // Check if there is a path from A to B
    if (bfs(start.first, start.second)) {
        cout << "YES" << endl << ans.size() << endl;
        while (!ans.empty()) {
            cout << ans.top();
            ans.pop();
        }
    }
    else
        cout << "NO" << endl;
}
Java
import java.util.*;

public class Main {
    static char[][] graph;
    static char[][] steps;
    static boolean[][] visited;
    static Stack<Character> ans;
    static Pair<Integer, Integer> start, dest;
    static int n, m;

    // A Pair class to store coordinates
    static class Pair<X, Y> {
        X first;
        Y second;

        Pair(X first, Y second)
        {
            this.first = first;
            this.second = second;
        }
    }

    // Function to check whether the current cell is
    // unvisited, unblocked and inside the grid
    static boolean isValid(int x, int y)
    {
        return (x >= 0 && x < n && y >= 0 && y < m
                && graph[x][y] != '#' && !visited[x][y]);
    }

    // Function to backtrack and extract the path from B to
    // A
    static void backtrack(int x, int y)
    {
        if (steps[x][y] != 'X') {
            char ch = steps[x][y];
            ans.push(ch);
            // Move one cell up
            if (ch == 'U')
                backtrack(x + 1, y);
            // Move one cell down
            else if (ch == 'D')
                backtrack(x - 1, y);
            // Move one cell left
            else if (ch == 'L')
                backtrack(x, y + 1);
            // Move one cell right
            else if (ch == 'R')
                backtrack(x, y - 1);
        }
    }

    // Function to run BFS and find the shortest path from A
    // to B
    static boolean bfs(int x, int y)
    {
        steps[x][y] = 'X';
        boolean flag = false;
        // Queue to run BFS across the grid
        Queue<Pair<Integer, Integer> > q
            = new LinkedList<>();
        q.add(new Pair<>(x, y));
        while (!q.isEmpty()) {
            Pair<Integer, Integer> ele = q.poll();
            x = ele.first;
            y = ele.second;
            // If we have reached the destination
            if (graph[x][y] == 'B') {
                flag = true;
                break;
            }
            visited[x][y] = true;
            // Move Up
            if (isValid(x - 1, y)) {
                visited[x - 1][y] = true;
                steps[x - 1][y] = 'U';
                q.add(new Pair<>(x - 1, y));
            }
            // Move Right
            if (isValid(x, y + 1)) {
                visited[x][y + 1] = true;
                steps[x][y + 1] = 'R';
                q.add(new Pair<>(x, y + 1));
            }
            // Move Down
            if (isValid(x + 1, y)) {
                visited[x + 1][y] = true;
                steps[x + 1][y] = 'D';
                q.add(new Pair<>(x + 1, y));
            }
            // Move Left
            if (isValid(x, y - 1)) {
                visited[x][y - 1] = true;
                steps[x][y - 1] = 'L';
                q.add(new Pair<>(x, y - 1));
            }
        }
        // If there is a path from A to B, print the path
        if (flag) {
            backtrack(x, y);
            return true;
        }
        else
            return false;
    }

    public static void main(String[] args)
    {
        // Sample Input
        n = 5;
        m = 8;
        graph = new char[][] { "########".toCharArray(),
                               "#.A#...#".toCharArray(),
                               "#.##.#B#".toCharArray(),
                               "#......#".toCharArray(),
                               "########".toCharArray() };

        visited = new boolean[n][m];
        steps = new char[n][m];
        ans = new Stack<>();

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (graph[i][j] == 'A')
                    start = new Pair<>(i, j);
                else if (graph[i][j] == 'B')
                    dest = new Pair<>(i, j);
            }
        }

        // Check if there is a path from A to B
        if (bfs(start.first, start.second)) {
            System.out.println("YES");
            System.out.println(ans.size());
            while (!ans.isEmpty()) {
                System.out.print(ans.pop());
            }
        }
        else
            System.out.println("NO");
    }
}
Python
from collections import deque


def is_valid(x, y):
    return (0 <= x < n and 0 <= y < m
            and graph[x][y] != '#' and not visited[x][y])
# Function to backtrack and extract the path from the B to A


def backtrack(x, y):
    if steps[x][y] != 'X':
        ch = steps[x][y]
        ans.append(ch)
        # Move one cell up
        if ch == 'U':
            backtrack(x + 1, y)
        # Move one cell down
        elif ch == 'D':
            backtrack(x - 1, y)
        # Move one cell left
        elif ch == 'L':
            backtrack(x, y + 1)
        elif ch == 'R':
            backtrack(x, y - 1)
# Function to run BFS and find the shortest path from the A to B


def bfs(x, y):
    steps[x][y] = 'X'
    flag = False
    # Queue to run BFS across the grid
    q = deque([(x, y)])
    while q:
        x, y = q.popleft()
        # If we have reached the destination
        if graph[x][y] == 'B':
            flag = True
            break
        visited[x][y] = True
        # Move Up
        if is_valid(x - 1, y):
            visited[x - 1][y] = True
            steps[x - 1][y] = 'U'
            q.append((x - 1, y))
        # Move Right
        if is_valid(x, y + 1):
            visited[x][y + 1] = True
            steps[x][y + 1] = 'R'
            q.append((x, y + 1))
        # Move Down
        if is_valid(x + 1, y):
            visited[x + 1][y] = True
            steps[x + 1][y] = 'D'
            q.append((x + 1, y))
        # Move Left
        if is_valid(x, y - 1):
            visited[x][y - 1] = True
            steps[x][y - 1] = 'L'
            q.append((x, y - 1))
    # If there is a path from the A to B
    # print the path
    if flag:
        backtrack(x, y)
        return True
    else:
        return False


# Sample Input
n = 5
m = 8
graph = ["########",
         "#.A#...#",
         "#.##.#B#",
         "#......#",
         "########"]
visited = [[False] * m for _ in range(n)]
steps = [[''] * m for _ in range(n)]
ans = []
for i in range(n):
    for j in range(m):
        if graph[i][j] == 'A':
            start = (i, j)
        elif graph[i][j] == 'B':
            dest = (i, j)
# Check if there is a path from A to B
if bfs(start[0], start[1]):
    print("YES")
    print(len(ans))
    while ans:
        print(ans.pop(), end="")
else:
    print("NO")
JavaScript
let n = 5, m = 8; 
// Dimensions of the grid
let graph = [
    "########",
    "#.A#...#",
    "#.##.#B#",
    "#......#",
    "########"
]; // Input grid
let start, dest; 
// Start and destination points
let steps = Array.from({ length: n }, () => Array(m).fill(''));
let visited = Array.from({ length: n }, () => Array(m).fill(false));
let ans = [];
// Function to check if the current cell is valid
const isValid = (x, y) => {
    return x >= 0 && x < n && y >= 0 && y < m && graph[x][y] !== '#' && !visited[x][y];
};
// Function to backtrack and extract the path from the B to A
const backtrack = (x, y) => {
    if (steps[x][y] !== 'X') {
        let ch = steps[x][y];
        ans.push(ch);
        if (ch === 'U') backtrack(x + 1, y);
        else if (ch === 'D') backtrack(x - 1, y);
        else if (ch === 'L') backtrack(x, y + 1);
        else if (ch === 'R') backtrack(x, y - 1);
    }
};
// Function to run BFS and find the shortest path from the A to B
const bfs = (x, y) => {
    steps[x][y] = 'X';
    let flag = false;
    let queue = [[x, y]];

    while (queue.length) {
        [x, y] = queue.shift();
        if (graph[x][y] === 'B') {
            flag = true; 
            // Destination reached
            break;
        }
        visited[x][y] = true;
        if (isValid(x - 1, y)) {
            visited[x - 1][y] = true;
            steps[x - 1][y] = 'U';
            queue.push([x - 1, y]);
        }
        // Move Right
        if (isValid(x, y + 1)) {
            visited[x][y + 1] = true;
            steps[x][y + 1] = 'R';
            queue.push([x, y + 1]);
        }
        // Move Down
        if (isValid(x + 1, y)) {
            visited[x + 1][y] = true;
            steps[x + 1][y] = 'D';
            queue.push([x + 1, y]);
        }
        // Move Left
        if (isValid(x, y - 1)) {
            visited[x][y - 1] = true;
            steps[x][y - 1] = 'L';
            queue.push([x, y - 1]);
        }
    }
    if (flag) {
        backtrack(x, y); 
        // Backtrack to the extract the path
        return true;
    }
    else return false;
};
// Find start and destination points
for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
        if (graph[i][j] === 'A') start = [i, j];
        else if (graph[i][j] === 'B') dest = [i, j];
    }
}
// Check if there is a path from the A to B
if (bfs(start[0], start[1])) {
    console.log("YES");
    console.log(ans.length);
    console.log(ans.reverse().join('')); 
    // Reverse and join the path
} else {
    console.log("NO");
}

Output
YES
9
LDDRRRRRU

Time Complexity: O(n*m)
Auxiliary Space: O(n*m)




Reffered: https://www.geeksforgeeks.org


Competitive Programming

Related
CSES Solutions – Reachable Nodes CSES Solutions – Reachable Nodes
LeetCode Contests Experience LeetCode Contests Experience
CSES Solutions - Prüfer Code CSES Solutions - Prüfer Code
CSES Solutions - Letter Pair Move Game CSES Solutions - Letter Pair Move Game
CSES Solutions - Path Queries CSES Solutions - Path Queries

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
16