Given a maze mat[][] of size n × m, where each cell is either:
'.' representing an empty cell, or
'#' representing an obstacle.
Find the number of distinct empty cells that Geek can visit starting from the cell (r, c).
Geek can move to any of the four adjacent cells (up, down, left, or right) from a cell, provided that the adjacent cell lies inside the maze and is not an obstacle.
Geek can make at most u upward moves and at most d downward on a path starting from [r, c]. Note that there can be multiple paths geek can follow to cover maximum distinct cells.
There is no limit on the number of left or right moves.
If the starting cell is an obstacle, return 0.
Examples:
Input: r = 1, c = 0, u = 1, d = 1, mat = [['.', '.', '.'], ['.', '#', '.'], ['#', '.', '.']]
Output: 5 Explanation: Geek starts from (1, 0) and follows the path (1,0)->(0,0)->(0,1)->(0,2)->(1,2). The cells (1,1) and (2,0) are obstacles, so they cannot be visited. Hence, Geek can visit 5 distinct empty cells.
Input: r = 2, c = 1, u = 2, d = 2, mat = [['.', '.', '.'], ['.', '#', '.'], ['.', '.', '.']]
Output: 8 Explanation: Geek starts from (2, 1) and follows the path (2,1)->(2,2)->(1,2)->(0,2)->(0,1)->(0,0)->(1,0)->(2,0). The cell (1,1) is an obstacle, so it cannot be visited. Hence, Geek can visit all 8 empty cells.
[Naive Approach]Using Depth First Search(DFS) - O(n * m * u * d) Time and O(n * m * u * d) Space
The idea is to explore the maze using DFS and try all four possible moves from every cell. Since the same cell can be reached with different numbers of upward and downward moves remaining, the state must include both resources along with the cell position. Therefore, we use solve(r, c, uLeft, dLeft) and mark each complete state as visited. A separate reachable matrix records whether a cell has been reached through at least one valid state.
Start DFS from (r, c) with u upward and d downward moves available.
Treat (r, c, uLeft, dLeft) as the complete state and mark it as visited.
Mark the current cell as reachable.
Recursively move up and down after decreasing their respective move limits.
Recursively move left and right without changing the move limits.
Finally, count all cells marked as reachable.
C++
#include<bits/stdc++.h>usingnamespacestd;// DFS using the complete state:// (row, column, remaining upward moves, remaining downward moves)voiddfs(intr,intc,intuLeft,intdLeft,vector<vector<char>>&mat,vector<vector<vector<vector<bool>>>>&visited,vector<vector<bool>>&reachable){intn=mat.size();intm=mat[0].size();// Check for invalid cell or obstacle.if(r<0||r>=n||c<0||c>=m||mat[r][c]=='#'){return;}// If this exact state has already been processed.if(visited[r][c][uLeft][dLeft]){return;}// Mark this state as visited.visited[r][c][uLeft][dLeft]=true;// The current cell is reachable.reachable[r][c]=true;// Move Up: consume one upward move.if(uLeft>0){dfs(r-1,c,uLeft-1,dLeft,mat,visited,reachable);}// Move Down: consume one downward move.if(dLeft>0){dfs(r+1,c,uLeft,dLeft-1,mat,visited,reachable);}// Move Left: no upward/downward move consumed.dfs(r,c-1,uLeft,dLeft,mat,visited,reachable);// Move Right: no upward/downward move consumed.dfs(r,c+1,uLeft,dLeft,mat,visited,reachable);}// Returns the number of distinct cells that can be visited.intnumberOfCells(intr,intc,intu,intd,vector<vector<char>>&mat){intn=mat.size();intm=mat[0].size();// If starting cell is an obstacle.if(mat[r][c]=='#'){return0;}// visited[r][c][uLeft][dLeft]vector<vector<vector<vector<bool>>>>visited(n,vector<vector<vector<bool>>>(m,vector<vector<bool>>(u+1,vector<bool>(d+1,false))));// Stores whether each cell can be reached.vector<vector<bool>>reachable(n,vector<bool>(m,false));// Start DFS with all moves available.dfs(r,c,u,d,mat,visited,reachable);// Count distinct reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(reachable[i][j]){ans++;}}}returnans;}intmain(){vector<vector<char>>mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;cout<<numberOfCells(r,c,u,d,mat)<<endl;return0;}
Java
classGFG{// DFS using state:// (row, column, remaining upward moves, remaining// downward moves)staticvoiddfs(intr,intc,intuLeft,intdLeft,char[][]mat,boolean[][][][]visited,boolean[][]reachable){intn=mat.length;intm=mat[0].length;// Invalid cell or obstacle.if(r<0||r>=n||c<0||c>=m||mat[r][c]=='#'){return;}// Same state has already been processed.if(visited[r][c][uLeft][dLeft]){return;}// Mark this state as visited.visited[r][c][uLeft][dLeft]=true;// Mark cell as reachable.reachable[r][c]=true;// Move Up.if(uLeft>0){dfs(r-1,c,uLeft-1,dLeft,mat,visited,reachable);}// Move Down.if(dLeft>0){dfs(r+1,c,uLeft,dLeft-1,mat,visited,reachable);}// Move Left.dfs(r,c-1,uLeft,dLeft,mat,visited,reachable);// Move Right.dfs(r,c+1,uLeft,dLeft,mat,visited,reachable);}staticintnumberOfCells(intr,intc,intu,intd,char[][]mat){intn=mat.length;intm=mat[0].length;// Starting cell is blocked.if(mat[r][c]=='#'){return0;}// visited[row][col][remainingUp][remainingDown]boolean[][][][]visited=newboolean[n][m][u+1][d+1];// Stores distinct reachable cells.boolean[][]reachable=newboolean[n][m];// Start DFS.dfs(r,c,u,d,mat,visited,reachable);// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(reachable[i][j]){ans++;}}}returnans;}// Main functionpublicstaticvoidmain(String[]args){char[][]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;System.out.println(numberOfCells(r,c,u,d,mat));}}
Python
# DFS using state:# (row, column, remaining upward moves, remaining downward moves)defdfs(r,c,u_left,d_left,mat,visited,reachable):n=len(mat)m=len(mat[0])# Invalid cell or obstacle.if(r<0orr>=norc<0orc>=mormat[r][c]=='#'):return# Same state has already been processed.ifvisited[r][c][u_left][d_left]:return# Mark this state as visited.visited[r][c][u_left][d_left]=True# Mark cell as reachable.reachable[r][c]=True# Move Up.ifu_left>0:dfs(r-1,c,u_left-1,d_left,mat,visited,reachable)# Move Down.ifd_left>0:dfs(r+1,c,u_left,d_left-1,mat,visited,reachable)# Move Left.dfs(r,c-1,u_left,d_left,mat,visited,reachable)# Move Right.dfs(r,c+1,u_left,d_left,mat,visited,reachable)# Returns the number of distinct reachable cells.defnumberOfCells(r,c,u,d,mat):n=len(mat)m=len(mat[0])# Starting cell is blocked.ifmat[r][c]=='#':return0# visited[row][col][remainingUp][remainingDown]visited=[[[[Falsefor_inrange(d+1)]for_inrange(u+1)]for_inrange(m)]for_inrange(n)]# Stores distinct reachable cells.reachable=[[Falsefor_inrange(m)]for_inrange(n)]# Start DFS.dfs(r,c,u,d,mat,visited,reachable)# Count reachable cells.ans=0foriinrange(n):forjinrange(m):ifreachable[i][j]:ans+=1returnans# Driver Codeif__name__=="__main__":mat=[['.','.','.'],['.','#','.'],['#','.','.']]r=1c=0u=1d=1print(numberOfCells(r,c,u,d,mat))
C#
usingSystem;classGFG{// DFS using state:// (row, column, remaining upward moves, remaining// downward moves)staticvoidDfs(intr,intc,intuLeft,intdLeft,char[,]mat,bool[,,,]visited,bool[,]reachable){intn=mat.GetLength(0);intm=mat.GetLength(1);// Invalid cell or obstacle.if(r<0||r>=n||c<0||c>=m||mat[r,c]=='#'){return;}// Same state has already been processed.if(visited[r,c,uLeft,dLeft]){return;}// Mark this state as visited.visited[r,c,uLeft,dLeft]=true;// Mark cell as reachable.reachable[r,c]=true;// Move Up.if(uLeft>0){Dfs(r-1,c,uLeft-1,dLeft,mat,visited,reachable);}// Move Down.if(dLeft>0){Dfs(r+1,c,uLeft,dLeft-1,mat,visited,reachable);}// Move Left.Dfs(r,c-1,uLeft,dLeft,mat,visited,reachable);// Move Right.Dfs(r,c+1,uLeft,dLeft,mat,visited,reachable);}staticintnumberOfCells(intr,intc,intu,intd,char[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);// Starting cell is blocked.if(mat[r,c]=='#'){return0;}// visited[row][col][remainingUp][remainingDown]bool[,,,]visited=newbool[n,m,u+1,d+1];// Stores distinct reachable cells.bool[,]reachable=newbool[n,m];// Start DFS.Dfs(r,c,u,d,mat,visited,reachable);// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(reachable[i,j]){ans++;}}}returnans;}// Main functionpublicstaticvoidMain(){char[,]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;Console.WriteLine(numberOfCells(r,c,u,d,mat));}}
JavaScript
// DFS using state:// (row, column, remaining upward moves, remaining downward moves)functiondfs(r,c,uLeft,dLeft,mat,visited,reachable){constn=mat.length;constm=mat[0].length;// Invalid cell or obstacle.if(r<0||r>=n||c<0||c>=m||mat[r][c]==='#'){return;}// Same state has already been processed.if(visited[r][c][uLeft][dLeft]){return;}// Mark this state as visited.visited[r][c][uLeft][dLeft]=true;// Mark cell as reachable.reachable[r][c]=true;// Move Up.if(uLeft>0){dfs(r-1,c,uLeft-1,dLeft,mat,visited,reachable);}// Move Down.if(dLeft>0){dfs(r+1,c,uLeft,dLeft-1,mat,visited,reachable);}// Move Left.dfs(r,c-1,uLeft,dLeft,mat,visited,reachable);// Move Right.dfs(r,c+1,uLeft,dLeft,mat,visited,reachable);}// Returns the number of distinct reachable cells.functionnumberOfCells(r,c,u,d,mat){constn=mat.length;constm=mat[0].length;// Starting cell is blocked.if(mat[r][c]==='#'){return0;}// visited[row][col][remainingUp][remainingDown]constvisited=Array.from({length:n},()=>Array.from({length:m},()=>Array.from({length:u+1},()=>Array(d+1).fill(false))));// Stores distinct reachable cells.constreachable=Array.from({length:n},()=>Array(m).fill(false));// Start DFS.dfs(r,c,u,d,mat,visited,reachable);// Count reachable cells.letans=0;for(leti=0;i<n;i++){for(letj=0;j<m;j++){if(reachable[i][j]){ans++;}}}returnans;}// Driver Codeconstmat=[['.','.','.'],['.','#','.'],['#','.','.']];constr=1;constc=0;constu=1;constd=1;console.log(numberOfCells(r,c,u,d,mat));
Output
5
Note: The above DFS approach uses a 4D visited array of size n × m × (u + 1) × (d + 1). Although this correctly tracks the state of the DFS, it can require a very large amount of memory when n, m, u, or d are large. As a result, it may cause an Out of Memory (SIGABRT) error on large test cases. Therefore, this approach should be avoided when the constraints are large.
[Better Approach] Using Priority Queue - O(n * m * log(n * m)) Time and O(n * m) Space
Instead of storing uLeft and dLeft as part of a 4D state, the idea is to use a priority queue to process cells in the order of the smallest number of upward moves used, followed by downward moves. For a fixed destination cell, the number of up and down moves are related by its row, so a state with fewer upward moves is always preferable. Therefore, the first time a cell is reached, we can mark it visited and avoid processing it again.
Initialize a min-priority queue with the starting state (0, 0, r, c).
Store (upUsed, downUsed, row, col) and prioritize fewer upward, then fewer downward moves.
For an upward/downward move, increase the corresponding move count if its limit is not exceeded.
For left/right moves, keep both move counts unchanged.
Mark a cell visited when it is first inserted into the priority queue.
Finally, count all visited cells.
C++
#include<bits/stdc++.h>usingnamespacestd;// Check whether a cell lies inside the maze.boolisValid(intr,intc,intn,intm){returnr>=0&&r<n&&c>=0&&c<m;}// Returns the number of distinct cells Geek can visit.intnumberOfCells(intr,intc,intu,intd,vector<vector<char>>&mat){intn=mat.size();intm=mat[0].size();// Starting cell is blocked.if(mat[r][c]=='#'){return0;}/* State stored in priority queue: {upUsed, downUsed, row, col} Priority: 1. Smaller upUsed 2. Smaller downUsed */priority_queue<vector<int>,vector<vector<int>>,greater<vector<int>>>pq;// visited[row][col] tells whether the cell// has already been reached.vector<vector<bool>>visited(n,vector<bool>(m,false));// Start from the given cell.pq.push({0,0,r,c});visited[r][c]=true;while(!pq.empty()){vector<int>current=pq.top();pq.pop();intupUsed=current[0];intdownUsed=current[1];intx=current[2];inty=current[3];// Move Up.if(isValid(x-1,y,n,m)&&!visited[x-1][y]&&mat[x-1][y]=='.'&&upUsed<u){visited[x-1][y]=true;pq.push({upUsed+1,downUsed,x-1,y});}// Move Down.if(isValid(x+1,y,n,m)&&!visited[x+1][y]&&mat[x+1][y]=='.'&&downUsed<d){visited[x+1][y]=true;pq.push({upUsed,downUsed+1,x+1,y});}// Move Left.if(isValid(x,y-1,n,m)&&!visited[x][y-1]&&mat[x][y-1]=='.'){visited[x][y-1]=true;pq.push({upUsed,downUsed,x,y-1});}// Move Right.if(isValid(x,y+1,n,m)&&!visited[x][y+1]&&mat[x][y+1]=='.'){visited[x][y+1]=true;pq.push({upUsed,downUsed,x,y+1});}}// Count all reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(visited[i][j]){ans++;}}}returnans;}intmain(){vector<vector<char>>mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;cout<<numberOfCells(r,c,u,d,mat)<<endl;return0;}
Java
importjava.util.*;classGFG{// Check whether a cell is inside the maze.staticbooleanisValid(intr,intc,intn,intm){returnr>=0&&r<n&&c>=0&&c<m;}// Returns the number of distinct cells Geek can visit.staticintnumberOfCells(intr,intc,intu,intd,char[][]mat){intn=mat.length;intm=mat[0].length;// Starting cell is blocked.if(mat[r][c]=='#'){return0;}/* * State: * {upUsed, downUsed, row, col} * * Priority: * 1. Smaller upUsed * 2. Smaller downUsed */PriorityQueue<int[]>pq=newPriorityQueue<>((a,b)->{if(a[0]!=b[0])returnInteger.compare(a[0],b[0]);returnInteger.compare(a[1],b[1]);});// visited[row][col]boolean[][]visited=newboolean[n][m];// Start from the given cell.pq.offer(newint[]{0,0,r,c});visited[r][c]=true;while(!pq.isEmpty()){int[]current=pq.poll();intupUsed=current[0];intdownUsed=current[1];intx=current[2];inty=current[3];// Move Up.if(isValid(x-1,y,n,m)&&!visited[x-1][y]&&mat[x-1][y]=='.'&&upUsed<u){visited[x-1][y]=true;pq.offer(newint[]{upUsed+1,downUsed,x-1,y});}// Move Down.if(isValid(x+1,y,n,m)&&!visited[x+1][y]&&mat[x+1][y]=='.'&&downUsed<d){visited[x+1][y]=true;pq.offer(newint[]{upUsed,downUsed+1,x+1,y});}// Move Left.if(isValid(x,y-1,n,m)&&!visited[x][y-1]&&mat[x][y-1]=='.'){visited[x][y-1]=true;pq.offer(newint[]{upUsed,downUsed,x,y-1});}// Move Right.if(isValid(x,y+1,n,m)&&!visited[x][y+1]&&mat[x][y+1]=='.'){visited[x][y+1]=true;pq.offer(newint[]{upUsed,downUsed,x,y+1});}}// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(visited[i][j]){ans++;}}}returnans;}// Main functionpublicstaticvoidmain(String[]args){char[][]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;System.out.println(numberOfCells(r,c,u,d,mat));}}
Python
importheapq# Check whether a cell is inside the maze.defisValid(r,c,n,m):return0<=r<nand0<=c<m# Returns the number of distinct cells Geek can visit.defnumberOfCells(r,c,u,d,mat):n=len(mat)m=len(mat[0])# Starting cell is blocked.ifmat[r][c]=='#':return0# Min heap.# State: (upUsed, downUsed, row, col)pq=[]# Start from the given cell.heapq.heappush(pq,(0,0,r,c))# visited[row][col]visited=[[False]*mfor_inrange(n)]visited[r][c]=Truewhilepq:upUsed,downUsed,x,y=heapq.heappop(pq)# Move Up.if(isValid(x-1,y,n,m)andnotvisited[x-1][y]andmat[x-1][y]=='.'andupUsed<u):visited[x-1][y]=Trueheapq.heappush(pq,(upUsed+1,downUsed,x-1,y))# Move Down.if(isValid(x+1,y,n,m)andnotvisited[x+1][y]andmat[x+1][y]=='.'anddownUsed<d):visited[x+1][y]=Trueheapq.heappush(pq,(upUsed,downUsed+1,x+1,y))# Move Left.if(isValid(x,y-1,n,m)andnotvisited[x][y-1]andmat[x][y-1]=='.'):visited[x][y-1]=Trueheapq.heappush(pq,(upUsed,downUsed,x,y-1))# Move Right.if(isValid(x,y+1,n,m)andnotvisited[x][y+1]andmat[x][y+1]=='.'):visited[x][y+1]=Trueheapq.heappush(pq,(upUsed,downUsed,x,y+1))# Count reachable cells.ans=0foriinrange(n):forjinrange(m):ifvisited[i][j]:ans+=1returnans# Driver Codeif__name__=="__main__":mat=[['.','.','.'],['.','#','.'],['#','.','.']]r=1c=0u=1d=1print(numberOfCells(r,c,u,d,mat))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{// State used by the priority queue.// {upUsed, downUsed, row, col}classState:IComparable<State>{publicintup;publicintdown;publicintrow;publicintcol;publicState(intup,intdown,introw,intcol){this.up=up;this.down=down;this.row=row;this.col=col;}// Smaller up is preferred.// If equal, smaller down is preferred.publicintCompareTo(Stateother){if(up!=other.up)returnup.CompareTo(other.up);returndown.CompareTo(other.down);}}// Check whether a cell is inside the maze.staticboolIsValid(intr,intc,intn,intm){returnr>=0&&r<n&&c>=0&&c<m;}// Returns the number of distinct cells Geek can visit.staticintnumberOfCells(intr,intc,intu,intd,char[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);// Starting cell is blocked.if(mat[r,c]=='#'){return0;}// Min priority queue.varpq=newPriorityQueue<State,(int,int)>();// visited[row, col]bool[,]visited=newbool[n,m];// Start from the given cell.pq.Enqueue(newState(0,0,r,c),(0,0));visited[r,c]=true;while(pq.Count>0){Statecurrent=pq.Dequeue();intupUsed=current.up;intdownUsed=current.down;intx=current.row;inty=current.col;// Move Up.if(IsValid(x-1,y,n,m)&&!visited[x-1,y]&&mat[x-1,y]=='.'&&upUsed<u){visited[x-1,y]=true;pq.Enqueue(newState(upUsed+1,downUsed,x-1,y),(upUsed+1,downUsed));}// Move Down.if(IsValid(x+1,y,n,m)&&!visited[x+1,y]&&mat[x+1,y]=='.'&&downUsed<d){visited[x+1,y]=true;pq.Enqueue(newState(upUsed,downUsed+1,x+1,y),(upUsed,downUsed+1));}// Move Left.if(IsValid(x,y-1,n,m)&&!visited[x,y-1]&&mat[x,y-1]=='.'){visited[x,y-1]=true;pq.Enqueue(newState(upUsed,downUsed,x,y-1),(upUsed,downUsed));}// Move Right.if(IsValid(x,y+1,n,m)&&!visited[x,y+1]&&mat[x,y+1]=='.'){visited[x,y+1]=true;pq.Enqueue(newState(upUsed,downUsed,x,y+1),(upUsed,downUsed));}}// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(visited[i,j]){ans++;}}}returnans;}// Main functionpublicstaticvoidMain(){char[,]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;Console.WriteLine(numberOfCells(r,c,u,d,mat));}}
JavaScript
// MinHeap implementation.classMinHeap{constructor(){this.heap=[];}// Compare two states.// State = [upUsed, downUsed, row, col]compare(a,b){if(a[0]!==b[0]){returna[0]-b[0];}returna[1]-b[1];}// Insert an element into the heap.push(value){this.heap.push(value);leti=this.heap.length-1;while(i>0){letparent=Math.floor((i-1)/2);if(this.compare(this.heap[parent],this.heap[i])<=0){break;}[this.heap[parent],this.heap[i]]=[this.heap[i],this.heap[parent]];i=parent;}}// Remove and return the minimum element.pop(){if(this.heap.length===0){returnnull;}constroot=this.heap[0];constlast=this.heap.pop();if(this.heap.length>0){this.heap[0]=last;leti=0;while(true){letleft=2*i+1;letright=2*i+2;letsmallest=i;if(left<this.heap.length&&this.compare(this.heap[left],this.heap[smallest])<0){smallest=left;}if(right<this.heap.length&&this.compare(this.heap[right],this.heap[smallest])<0){smallest=right;}if(smallest===i){break;}[this.heap[i],this.heap[smallest]]=[this.heap[smallest],this.heap[i]];i=smallest;}}returnroot;}// Check whether the heap is empty.isEmpty(){returnthis.heap.length===0;}}// Check whether a cell is inside the maze.functionisValid(r,c,n,m){returnr>=0&&r<n&&c>=0&&c<m;}// Returns the number of distinct cells Geek can visit.functionnumberOfCells(r,c,u,d,mat){constn=mat.length;constm=mat[0].length;// Starting cell is blocked.if(mat[r][c]==="#"){return0;}constpq=newMinHeap();// visited[row][col]constvisited=Array.from({length:n},()=>Array(m).fill(false));// Start from the given cell.// State = [upUsed, downUsed, row, col]pq.push([0,0,r,c]);visited[r][c]=true;while(!pq.isEmpty()){const[upUsed,downUsed,x,y]=pq.pop();// Move Up.if(isValid(x-1,y,n,m)&&!visited[x-1][y]&&mat[x-1][y]==="."&&upUsed<u){visited[x-1][y]=true;pq.push([upUsed+1,downUsed,x-1,y]);}// Move Down.if(isValid(x+1,y,n,m)&&!visited[x+1][y]&&mat[x+1][y]==="."&&downUsed<d){visited[x+1][y]=true;pq.push([upUsed,downUsed+1,x+1,y]);}// Move Left.if(isValid(x,y-1,n,m)&&!visited[x][y-1]&&mat[x][y-1]==="."){visited[x][y-1]=true;pq.push([upUsed,downUsed,x,y-1]);}// Move Right.if(isValid(x,y+1,n,m)&&!visited[x][y+1]&&mat[x][y+1]==="."){visited[x][y+1]=true;pq.push([upUsed,downUsed,x,y+1]);}}// Count reachable cells.letans=0;for(leti=0;i<n;i++){for(letj=0;j<m;j++){if(visited[i][j]){ans++;}}}returnans;}// Driver Codeconstmat=[[".",".","."],[".","#","."],["#",".","."]];constr=1;constc=0;constu=1;constd=1;console.log(numberOfCells(r,c,u,d,mat));
Output
5
[Expected Approach] BFS with Minimum Up Moves - O(n * m) Time and O(n * m) Space
For every cell, store the minimum number of upward moves needed to reach it. Since moving up is the only movement that consumes the resource we need to minimize, reaching a cell with fewer upward moves always leaves us with at least as much flexibility for future moves. The number of downward moves can then be calculated from the row difference. Therefore, each cell only needs one best state instead of the huge 4D state used by the naive DFS.
Create upUsed[][], where each cell stores the minimum upward moves required to reach it.
Start BFS from (r, c) with upUsed[r][c] = 0.
For the current cell (x, y), calculate downUsed = upUsed[x][y] + (x - r).
Move to neighboring cells only when the corresponding up/down limit is satisfied and the new state improves upUsed.
Left/right moves keep upUsed unchanged, while moving up increases it by 1.
Count all cells whose upUsed value is not INT_MAX.
C++
#include<bits/stdc++.h>usingnamespacestd;// Returns the number of distinct cells Geek can visit.intnumberOfCells(intr,intc,intu,intd,vector<vector<char>>&mat){intn=mat.size();intm=mat[0].size();// Starting cell is blocked.if(mat[r][c]=='#'){return0;}/* upUsed[i][j] = minimum number of upward moves required to reach cell (i, j). */vector<vector<int>>upUsed(n,vector<int>(m,INT_MAX));queue<pair<int,int>>q;// Starting cell.upUsed[r][c]=0;q.push({r,c});while(!q.empty()){auto[x,y]=q.front();q.pop();// Number of upward moves used so far.intcurrUp=upUsed[x][y];/* From: downUsed - upUsed = currentRow - startRow Therefore: downUsed = currUp + (x - r) */intcurrDown=currUp+(x-r);// Move Up.if(x-1>=0&&mat[x-1][y]=='.'&&currUp+1<=u&&currUp+1<upUsed[x-1][y]){upUsed[x-1][y]=currUp+1;q.push({x-1,y});}// Move Down.if(x+1<n&&mat[x+1][y]=='.'&&currDown+1<=d&&currUp<upUsed[x+1][y]){upUsed[x+1][y]=currUp;q.push({x+1,y});}// Move Left.if(y-1>=0&&mat[x][y-1]=='.'&&currUp<upUsed[x][y-1]){upUsed[x][y-1]=currUp;q.push({x,y-1});}// Move Right.if(y+1<m&&mat[x][y+1]=='.'&&currUp<upUsed[x][y+1]){upUsed[x][y+1]=currUp;q.push({x,y+1});}}// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(upUsed[i][j]!=INT_MAX){ans++;}}}returnans;}intmain(){vector<vector<char>>mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;cout<<numberOfCells(r,c,u,d,mat)<<endl;return0;}
Java
importjava.util.*;classGFG{// Returns the number of distinct cells Geek can visit.staticintnumberOfCells(intr,intc,intu,intd,char[][]mat){intn=mat.length;intm=mat[0].length;// Starting cell is blocked.if(mat[r][c]=='#'){return0;}/* * upUsed[i][j] = minimum number of upward moves * required to reach cell (i, j). */int[][]upUsed=newint[n][m];for(inti=0;i<n;i++){Arrays.fill(upUsed[i],Integer.MAX_VALUE);}Queue<int[]>q=newLinkedList<>();// Starting cell.upUsed[r][c]=0;q.offer(newint[]{r,c});while(!q.isEmpty()){int[]current=q.poll();intx=current[0];inty=current[1];// Number of upward moves used so far.intcurrUp=upUsed[x][y];/* * downUsed - upUsed = currentRow - startRow * * Therefore: * * downUsed = currUp + (x - r) */intcurrDown=currUp+(x-r);// Move Up.if(x-1>=0&&mat[x-1][y]=='.'&&currUp+1<=u&&currUp+1<upUsed[x-1][y]){upUsed[x-1][y]=currUp+1;q.offer(newint[]{x-1,y});}// Move Down.if(x+1<n&&mat[x+1][y]=='.'&&currDown+1<=d&&currUp<upUsed[x+1][y]){upUsed[x+1][y]=currUp;q.offer(newint[]{x+1,y});}// Move Left.if(y-1>=0&&mat[x][y-1]=='.'&&currUp<upUsed[x][y-1]){upUsed[x][y-1]=currUp;q.offer(newint[]{x,y-1});}// Move Right.if(y+1<m&&mat[x][y+1]=='.'&&currUp<upUsed[x][y+1]){upUsed[x][y+1]=currUp;q.offer(newint[]{x,y+1});}}// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(upUsed[i][j]!=Integer.MAX_VALUE){ans++;}}}returnans;}// Main functionpublicstaticvoidmain(String[]args){char[][]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;System.out.println(numberOfCells(r,c,u,d,mat));}}
Python
fromcollectionsimportdeque# Returns the number of distinct cells Geek can visit.defnumberOfCells(r,c,u,d,mat):n=len(mat)m=len(mat[0])# Starting cell is blocked.ifmat[r][c]=='#':return0# upUsed[i][j] = minimum number of upward moves# required to reach cell (i, j).upUsed=[[float('inf')]*mfor_inrange(n)]q=deque()# Starting cell.upUsed[r][c]=0q.append((r,c))whileq:x,y=q.popleft()# Number of upward moves used so far.currUp=upUsed[x][y]# downUsed = currUp + (x - r)currDown=currUp+(x-r)# Move Up.if(x-1>=0andmat[x-1][y]=='.'andcurrUp+1<=uandcurrUp+1<upUsed[x-1][y]):upUsed[x-1][y]=currUp+1q.append((x-1,y))# Move Down.if(x+1<nandmat[x+1][y]=='.'andcurrDown+1<=dandcurrUp<upUsed[x+1][y]):upUsed[x+1][y]=currUpq.append((x+1,y))# Move Left.if(y-1>=0andmat[x][y-1]=='.'andcurrUp<upUsed[x][y-1]):upUsed[x][y-1]=currUpq.append((x,y-1))# Move Right.if(y+1<mandmat[x][y+1]=='.'andcurrUp<upUsed[x][y+1]):upUsed[x][y+1]=currUpq.append((x,y+1))# Count reachable cells.ans=0foriinrange(n):forjinrange(m):ifupUsed[i][j]!=float('inf'):ans+=1returnans# Driver Codeif__name__=="__main__":mat=[['.','.','.'],['.','#','.'],['#','.','.']]r=1c=0u=1d=1print(numberOfCells(r,c,u,d,mat))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{// Returns the number of distinct cells Geek can visit.staticintnumberOfCells(intr,intc,intu,intd,char[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);// Starting cell is blocked.if(mat[r,c]=='#'){return0;}/* * upUsed[i,j] = minimum number of upward moves * required to reach cell (i, j). */int[,]upUsed=newint[n,m];for(inti=0;i<n;i++){for(intj=0;j<m;j++){upUsed[i,j]=int.MaxValue;}}Queue<(int,int)>q=newQueue<(int,int)>();// Starting cell.upUsed[r,c]=0;q.Enqueue((r,c));while(q.Count>0){varcurrent=q.Dequeue();intx=current.Item1;inty=current.Item2;// Number of upward moves used so far.intcurrUp=upUsed[x,y];/* * downUsed - upUsed = currentRow - startRow * * Therefore: * * downUsed = currUp + (x - r) */intcurrDown=currUp+(x-r);// Move Up.if(x-1>=0&&mat[x-1,y]=='.'&&currUp+1<=u&&currUp+1<upUsed[x-1,y]){upUsed[x-1,y]=currUp+1;q.Enqueue((x-1,y));}// Move Down.if(x+1<n&&mat[x+1,y]=='.'&&currDown+1<=d&&currUp<upUsed[x+1,y]){upUsed[x+1,y]=currUp;q.Enqueue((x+1,y));}// Move Left.if(y-1>=0&&mat[x,y-1]=='.'&&currUp<upUsed[x,y-1]){upUsed[x,y-1]=currUp;q.Enqueue((x,y-1));}// Move Right.if(y+1<m&&mat[x,y+1]=='.'&&currUp<upUsed[x,y+1]){upUsed[x,y+1]=currUp;q.Enqueue((x,y+1));}}// Count reachable cells.intans=0;for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(upUsed[i,j]!=int.MaxValue){ans++;}}}returnans;}// Main functionpublicstaticvoidMain(){char[,]mat={{'.','.','.'},{'.','#','.'},{'#','.','.'}};intr=1;intc=0;intu=1;intd=1;Console.WriteLine(numberOfCells(r,c,u,d,mat));}}
JavaScript
// Returns the number of distinct cells Geek can visit.functionnumberOfCells(r,c,u,d,mat){constn=mat.length;constm=mat[0].length;// Starting cell is blocked.if(mat[r][c]==="#"){return0;}/* upUsed[i][j] = minimum number of upward moves required to reach cell (i, j). */constupUsed=Array.from({length:n},()=>Array(m).fill(Infinity));/* Queue implemented using an array and a pointer to avoid repeatedly removing the first element. */constq=[];letfront=0;// Starting cell.upUsed[r][c]=0;q.push([r,c]);while(front<q.length){const[x,y]=q[front++];// Number of upward moves used so far.constcurrUp=upUsed[x][y];/* downUsed = currUp + (x - r) */constcurrDown=currUp+(x-r);// Move Up.if(x-1>=0&&mat[x-1][y]==="."&&currUp+1<=u&&currUp+1<upUsed[x-1][y]){upUsed[x-1][y]=currUp+1;q.push([x-1,y]);}// Move Down.if(x+1<n&&mat[x+1][y]==="."&&currDown+1<=d&&currUp<upUsed[x+1][y]){upUsed[x+1][y]=currUp;q.push([x+1,y]);}// Move Left.if(y-1>=0&&mat[x][y-1]==="."&&currUp<upUsed[x][y-1]){upUsed[x][y-1]=currUp;q.push([x,y-1]);}// Move Right.if(y+1<m&&mat[x][y+1]==="."&&currUp<upUsed[x][y+1]){upUsed[x][y+1]=currUp;q.push([x,y+1]);}}// Count reachable cells.letans=0;for(leti=0;i<n;i++){for(letj=0;j<m;j++){if(upUsed[i][j]!==Infinity){ans++;}}}returnans;}// Driver Codeconstmat=[[".",".","."],[".","#","."],["#",".","."]];constr=1;constc=0;constu=1;constd=1;console.log(numberOfCells(r,c,u,d,mat));