CSES Solutions - Grid Paths
Last Updated :
11 Apr, 2024
There are 88418 paths in a 7x7 grid from the upper-left square to the lower-left square. Each path corresponds to a 48-character description consisting of characters D (down), U (up), L (left) and R (right). You are given a description of a path which may also contain characters ? (any direction). Your task is to calculate the number of paths that match the description.
Example
Input: ??????R??????U??????????????????????????LD????D?
Output: 201
Explanation: There are 201 possible paths with the given description.
Approach using DFS:
The idea is to use DFS and try all four directions if the current character in the string is ‘?’ else we go in direction given (L,R,U,D).
Pruning/Terminating the search in order to optimize the code:
If we cannot go up or down but can turn either left or right or if we cannot turn left or right but can go up and down, in this case the grid splits into two parts. It is clear that we cannot visit one part of the grid, so we can terminate the search. These four cases also leaves unvisited squares which can cannot be visited. Hence, the search needs to terminate.
- If the upper-right diagonal square is visited and the up and right squares are unvisited.
- If the lower-right diagonal square is visited and the down and right squares are unvisited.
- If the upper-left diagonal square is visited and the up and left squares are unvisited.
- If the lower-left diagonal square is visited and the down and right squares are unvisited.
Step-by-step algorithm:
- Define a function countPaths that takes the current position (x, y) and the current position in the path description string pos as parameters.
- Base Case Return 1:
- if all characters in the string have been processed and if the current position is the lower-left square else 0.
- Base Case Return 0:
- If the current cell has already been visited.
- If the current position is the lower-left square before processing all characters.
- If the current position is such that the up and down squares are unvisited and the left and right squares are visited.
- If the current position is such that the left and right squares are unvisited and the up and down squares are visited.
- If the current position is such that the upper-right diagonal square is visited and the up and right squares are unvisited.
- If the current position is such that the lower-right diagonal square is visited and the down and right squares are unvisited.
- If the current position is such that the upper-left diagonal square is visited and the up and left squares are unvisited.
- If the current position is such that the lower-left diagonal square is visited and the down and left squares are unvisited.
- Mark the current cell as visited.
- Initialize a variable to store the number of paths.
- Check if the current character in the string is ‘?’. If true, try all four directions.
- Check if the current character in the string is a direction (L,R,U,D). If true, go in that direction.
- Unmark the current cell.
- Return the number of paths.
Below is the implementation of the approach:
C++
// C++ Code
#include <bits/stdc++.h>
using namespace std;
// Macro to check if a coordinate is valid in the grid
#define isValid(a) (a >= 0 && a < 7 ? 1 : 0)
// Direction constants
#define right 0
#define left 1
#define down 2
#define up 3
// Direction vectors for right, left, down, and up
int dx[4] = { 0, 0, 1, -1 };
int dy[4] = { 1, -1, 0, 0 };
// The path description string
string str;
int vis[7][7];
// Function to count the number of paths that match the
// description
int countPaths(int x, int y, int pos)
{
// If we have processed all characters in the string and
// we are at the lower-left square, return 1
if (pos == (int)str.length())
return (x == 6 && y == 0);
// If we have reached the lower-left square before
// processing all characters, return 0
if (x == 6 && y == 0)
return 0;
// If the current cell is already visited, return 0
if (vis[x][y])
return 0;
// Array to keep track of the visited status of the
// neighboring cells
vector<bool> visited(4, -1);
for (int k = 0; k < 4; k++)
if (isValid(x + dx[k]) && isValid(y + dy[k]))
visited[k] = vis[x + dx[k]][y + dy[k]];
// If we are at a position such that the up and down
// squares are unvisited and the left and right squares
// are visited return 0
if (!visited[down] && !visited[up] && visited[right]
&& visited[left])
return 0;
// If we are at a position such that the left and right
// squares are unvisited and the up and down squares are
// visited return 0
if (!visited[right] && !visited[left] && visited[down]
&& visited[up])
return 0;
// If we are at a position such that the upper-right
// diagonal square is visited and the up and right
// squares are unvisited return 0
if (isValid(x - 1) && isValid(y + 1)
&& vis[x - 1][y + 1] == 1)
if (!visited[right] && !visited[up])
return 0;
// If we are at a position such that the lower-right
// diagonal square is visited and the down and right
// squares are unvisited return 0
if (isValid(x + 1) && isValid(y + 1)
&& vis[x + 1][y + 1] == 1)
if (!visited[right] && !visited[down])
return 0;
// If we are at a position such that the upper-left
// diagonal square is visited and the up and left
// squares are unvisited return 0
if (isValid(x - 1) && isValid(y - 1)
&& vis[x - 1][y - 1] == 1)
if (!visited[left] && !visited[up])
return 0;
// If we are at a position such that the lower-left diagonal
// square is visited and the down and right squares are
// unvisited return 0
if (isValid(x + 1) && isValid(y - 1)
&& vis[x + 1][y - 1] == 1)
if (!visited[left] && !visited[down])
return 0;
// Mark the current cell as visited
vis[x][y] = 1;
// Variable to store the number of paths
int numberOfPaths = 0;
// If the current character is '?', try all four
// directions
if (str[pos] == '?') {
for (int k = 0; k < 4; k++)
if (isValid(x + dx[k]) && isValid(y + dy[k]))
numberOfPaths += countPaths(
x + dx[k], y + dy[k], pos + 1);
}
// If the current character is a direction, go in that
// direction
else if (str[pos] == 'R' && y + 1 < 7)
numberOfPaths += countPaths(x, y + 1, pos + 1);
else if (str[pos] == 'L' && y - 1 >= 0)
numberOfPaths += countPaths(x, y - 1, pos + 1);
else if (str[pos] == 'U' && x - 1 >= 0)
numberOfPaths += countPaths(x - 1, y, pos + 1);
else if (str[pos] == 'D' && x + 1 < 7)
numberOfPaths += countPaths(x + 1, y, pos + 1);
// Unmark the current cell
vis[x][y] = 0;
// Return the number of paths
return numberOfPaths;
}
// Driver Code
int main()
{
// Example 1:
str = "??????R??????U??????????????????????????LD????"
"D?";
cout << countPaths(0, 0, 0) << endl;
}
Java
public class Main {
// Constants
private static final int DIR_LEN = 4;
private static final int[] dr = {-1, 0, 1, 0};
private static final int[] dc = {0, 1, 0, -1};
private static final int PATH_LEN = 48; // Length of all possible paths
private static final int GRID_SIZE = 9;
// Variables
private static int[] p = new int[PATH_LEN];
private static boolean[][] onPath = new boolean[GRID_SIZE][GRID_SIZE];
public static int tryPath(int pathIdx, int curR, int curC) {
// Optimization 3
if ((onPath[curR][curC - 1] && onPath[curR][curC + 1]) &&
(!onPath[curR - 1][curC] && !onPath[curR + 1][curC]))
return 0;
if ((onPath[curR - 1][curC] && onPath[curR + 1][curC]) &&
(!onPath[curR][curC - 1] && !onPath[curR][curC + 1]))
return 0;
if (curR == 7 && curC == 1) { // Reached endpoint before visiting all
if (pathIdx == PATH_LEN) return 1;
return 0;
}
if (pathIdx == PATH_LEN) return 0;
int ret = 0;
onPath[curR][curC] = true;
// Turn already determined:
if (p[pathIdx] < 4) {
int nxtR = curR + dr[p[pathIdx]];
int nxtC = curC + dc[p[pathIdx]];
if (!onPath[nxtR][nxtC]) ret += tryPath(pathIdx + 1, nxtR, nxtC);
} else { // Iterate through all four possible turns
for (int i = 0; i < DIR_LEN; i++) {
int nxtR = curR + dr[i];
int nxtC = curC + dc[i];
if (onPath[nxtR][nxtC]) continue;
ret += tryPath(pathIdx + 1, nxtR, nxtC);
}
}
// Reset and return
onPath[curR][curC] = false;
return ret;
}
public static void main(String[] args) {
String line = "??????R??????U??????????????????????????LD????D?";
// Convert path to ints
for (int i = 0; i < PATH_LEN; i++) {
char cur = line.charAt(i);
if (cur == 'U') p[i] = 0;
else if (cur == 'R') p[i] = 1;
else if (cur == 'D') p[i] = 2;
else if (cur == 'L') p[i] = 3;
else p[i] = 4; // cur == '?'
}
// Set borders of grid
for (int i = 0; i < GRID_SIZE; i++) {
onPath[0][i] = true;
onPath[8][i] = true;
onPath[i][0] = true;
onPath[i][8] = true;
}
// Initialize the inside of the grid to be completely empty
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
onPath[i][j] = false;
}
}
int startIdx = 0;
int startR = 1;
int startC = 1; // Always start path at (1, 1)
int ans = tryPath(startIdx, startR, startC);
System.out.println(ans);
}
}
//This code is contrbiuted by Utkarsh
Python3
# Import the necessary libraries
import numpy as np
# Direction vectors for right, left, down, and up
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
# The path description string
str_path = "??????R??????U??????????????????????????LD????D?"
# Initialize the visited array
vis = np.zeros((7, 7))
# Function to check if a coordinate is valid in the grid
def isValid(a):
return 1 if a >= 0 and a < 7 else 0
# Function to count the number of paths that match the description
def countPaths(x, y, pos):
# If we have processed all characters in the string and we are at the lower-left square, return 1
if pos == len(str_path):
return 1 if x == 6 and y == 0 else 0
# If we have reached the lower-left square before processing all characters, return 0
if x == 6 and y == 0:
return 0
# If the current cell is already visited, return 0
if vis[x][y]:
return 0
# Array to keep track of the visited status of the neighboring cells
visited = [-1]*4
for k in range(4):
if isValid(x + dx[k]) and isValid(y + dy[k]):
visited[k] = vis[x + dx[k]][y + dy[k]]
# If we are at a position such that the up and down squares are unvisited and the left and right squares are visited return 0
if not visited[2] and not visited[3] and visited[0] and visited[1]:
return 0
# If we are at a position such that the left and right squares are unvisited and the up and down squares are visited return 0
if not visited[0] and not visited[1] and visited[2] and visited[3]:
return 0
# If we are at a position such that the upper-right diagonal square is visited and the up and right squares are unvisited return 0
if isValid(x - 1) and isValid(y + 1) and vis[x - 1][y + 1] == 1:
if not visited[0] and not visited[3]:
return 0
# If we are at a position such that the lower-right diagonal square is visited and the down and right squares are unvisited return 0
if isValid(x + 1) and isValid(y + 1) and vis[x + 1][y + 1] == 1:
if not visited[0] and not visited[2]:
return 0
# If we are at a position such that the upper-left diagonal square is visited and the up and left squares are unvisited return 0
if isValid(x - 1) and isValid(y - 1) and vis[x - 1][y - 1] == 1:
if not visited[1] and not visited[3]:
return 0
# If we are at a position such that the lower-left diagonal square is visited and the down and right squares are unvisited return 0
if isValid(x + 1) and isValid(y - 1) and vis[x + 1][y - 1] == 1:
if not visited[1] and not visited[2]:
return 0
# Mark the current cell as visited
vis[x][y] = 1
# Variable to store the number of paths
numberOfPaths = 0
# If the current character is '?', try all four directions
if str_path[pos] == '?':
for k in range(4):
if isValid(x + dx[k]) and isValid(y + dy[k]):
numberOfPaths += countPaths(x + dx[k], y + dy[k], pos + 1)
# If the current character is a direction, go in that direction
elif str_path[pos] == 'R' and y + 1 < 7:
numberOfPaths += countPaths(x, y + 1, pos + 1)
elif str_path[pos] == 'L' and y - 1 >= 0:
numberOfPaths += countPaths(x, y - 1, pos + 1)
elif str_path[pos] == 'U' and x - 1 >= 0:
numberOfPaths += countPaths(x - 1, y, pos + 1)
elif str_path[pos] == 'D' and x + 1 < 7:
numberOfPaths += countPaths(x + 1, y, pos + 1)
# Unmark the current cell
vis[x][y] = 0
# Return the number of paths
return numberOfPaths
# Call the function and print the result
print(countPaths(0, 0, 0))
JavaScript
// Macro to check if a coordinate is valid in the grid
const isValid = (a) => (a >= 0 && a < 7 ? 1 : 0);
// Direction constants
const right = 0;
const left = 1;
const down = 2;
const up = 3;
// Direction vectors for right, left, down, and up
const dx = [0, 0, 1, -1];
const dy = [1, -1, 0, 0];
// The path description string
let str;
const vis = new Array(7).fill(null).map(() => new Array(7).fill(0));
// Function to count the number of paths that match the
// description
function countPaths(x, y, pos) {
// If we have processed all characters in the string and
// we are at the lower-left square, return 1
if (pos === str.length)
return (x === 6 && y === 0) ? 1 : 0;
// If we have reached the lower-left square before
// processing all characters, return 0
if (x === 6 && y === 0)
return 0;
// If the current cell is already visited, return 0
if (vis[x][y])
return 0;
// Array to keep track of the visited status of the
// neighboring cells
const visited = new Array(4).fill(-1);
for (let k = 0; k < 4; k++)
if (isValid(x + dx[k]) && isValid(y + dy[k]))
visited[k] = vis[x + dx[k]][y + dy[k]];
// If we are at a position such that the up and down
// squares are unvisited and the left and right squares
// are visited return 0
if (!visited[down] && !visited[up] && visited[right]
&& visited[left])
return 0;
// If we are at a position such that the left and right
// squares are unvisited and the up and down squares are
// visited return 0
if (!visited[right] && !visited[left] && visited[down]
&& visited[up])
return 0;
// If we are at a position such that the upper-right
// diagonal square is visited and the up and right
// squares are unvisited return 0
if (isValid(x - 1) && isValid(y + 1)
&& vis[x - 1][y + 1] === 1)
if (!visited[right] && !visited[up])
return 0;
// If we are at a position such that the lower-right
// diagonal square is visited and the down and right
// squares are unvisited return 0
if (isValid(x + 1) && isValid(y + 1)
&& vis[x + 1][y + 1] === 1)
if (!visited[right] && !visited[down])
return 0;
// If we are at a position such that the upper-left
// diagonal square is visited and the up and left
// squares are unvisited return 0
if (isValid(x - 1) && isValid(y - 1)
&& vis[x - 1][y - 1] === 1)
if (!visited[left] && !visited[up])
return 0;
// If we are at a position such that the lower-left diagonal
// square is visited and the down and right squares are
// unvisited return 0
if (isValid(x + 1) && isValid(y - 1)
&& vis[x + 1][y - 1] === 1)
if (!visited[left] && !visited[down])
return 0;
// Mark the current cell as visited
vis[x][y] = 1;
// Variable to store the number of paths
let numberOfPaths = 0;
// If the current character is '?', try all four
// directions
if (str[pos] === '?') {
for (let k = 0; k < 4; k++)
if (isValid(x + dx[k]) && isValid(y + dy[k]))
numberOfPaths += countPaths(
x + dx[k], y + dy[k], pos + 1);
}
// If the current character is a direction, go in that
// direction
else if (str[pos] === 'R' && y + 1 < 7)
numberOfPaths += countPaths(x, y + 1, pos + 1);
else if (str[pos] === 'L' && y - 1 >= 0)
numberOfPaths += countPaths(x, y - 1, pos + 1);
else if (str[pos] === 'U' && x - 1 >= 0)
numberOfPaths += countPaths(x - 1, y, pos + 1);
else if (str[pos] === 'D' && x + 1 < 7)
numberOfPaths += countPaths(x + 1, y, pos + 1);
// Unmark the current cell
vis[x][y] = 0;
// Return the number of paths
return numberOfPaths;
}
// Driver Code
(function main() {
// Example 1:
str = "??????R??????U??????????????????????????LD????D?";
console.log(countPaths(0, 0, 0));
})();
Time Complexity: O(4N), where N is the length of string.
Auxiliary Space: O(N)
Similar Reads
CSES Solutions - Grid Paths (DP)
Consider an N X N grid whose squares may have traps. It is not allowed to move to a square with a trap. Your task is to calculate the number of paths from the upper-left square to the lower-right square. You can only move right or down. Note: '.' denotes an empty cell, and '*' denotes a trap. Grid P
7 min read
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), #
11 min read
CSES Solutions - Swap Game
You are given a 3X3 grid containing the numbers 1,2...9. Your task is to perform a sequence of moves so that the grid will look like this: 1 2 34 5 67 8 9On each move, you can swap the numbers in any two adjacent squares (horizontally or vertically). What is the minimum number of moves required? Exa
10 min read
CSES Solutions - Number Spiral
A number spiral is an infinite grid whose upper-left square has the number 1. The task is to find the number in row Y and column X. Here are the first five layers of the spiral: Examples: Input:Â Y = 2, X = 3Output:Â 8Explanation: The 2nd row, 3rd column contains 8. Input:Â Y = 4, X = 2Output:Â 15Explan
9 min read
Pure CSS Responsive Grids
Pure CSS is a free and open-source framework of CSS. CSS Grid Layout is a method designed for the two-dimensional layout of items with rows and columns. It consists of both unresponsive and responsive modules. Responsive design's function is to display the contents of the website automatically acros
4 min read
What is CSS Grid?
CSS Grid is the powerful layout property in CSS that allows the web developers to design the complex and responsive grid-based layout. Unlike the older layout systems like Flexbox, which focuses on one dimensional layouts. CSS Grid is the two dimensional system, means that it can handle simultaneous
4 min read
CSS grid-row Property
The grid-row property in CSS is used to define the size and position of a grid item within a grid layout. It combines the grid-row-start and grid-row-end properties to specify the item's start and end positions along the row axis.Syntax:grid-row: grid-row-start|grid-row-end;Property Values1. grid-ro
3 min read
How To Use Tailwind CSS Grid?
Tailwind CSS can provide a highly customizable and low-level framework to build responsive and dynamic web layouts using the utility-first classes. One of the most powerful layout systems provided by Tailwind is CSS Grid, which allows developers to create complex and flexible grid-based layouts with
4 min read
CSS grid Property
It is a CSS property that offers a grid-based layout system, with rows and columns, making it easier to design web pages without floats and positioning. Try It: .item { border: 1px solid gray; font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; border-radius: 3px; margin:
4 min read
Pure CSS Grids
While creating a genuine responsive website layout the grid system is a crucial tool for web developers. A grid is a set of classes that helps us to divide the width of the screen or display into smaller units and make the website look responsive on various devices. Pure.CSS also comes up with such
4 min read