Castle On The Grid
Castle On The Grid
Problem Approach
Breadth First Search Approach using Precomputation:
Breadth-First Search (BFS) is a level-order traversal technique used in graphs and trees. It
explores all neighbors of a node before moving to the next level. BFS guarantees the shortest
path in unweighted graphs.
Precomputation in BFS
Precomputation is used to store useful results during BFS to answer future queries efficiently.
Key Idea
Instead of running BFS from scratch for every query, we precompute shortest paths,
reachability, or distances from a given source or multiple sources.
(r+1,c)
Precompute the furthest reachable position in each // Store the precomputed reachable position
direction
furthestX[i][j][dir] = newX;
void precompute(int m, int n, char grid[100][100], int
furthestX[100][100][4], int furthestY[100][100][4]) {
furthestY[i][j][dir] = newY;
for (int i = 0; i < m; i++) { }
for (int j = 0; j < n; j++) { }
if (grid[i][j] == 'X') continue; // Ignore obstacles }
}
for (int dir = 0; dir < 4; dir++) {
int newX = i, newY = j;
while (true) {
int nextX = newX + dx[dir];
int nextY = newY + dy[dir];
if (nextX < 0 || nextX >= m || nextY < 0 ||
nextY >= n || grid[nextX][nextY] == 'X')
break;
newX = nextX;
newY = nextY;
}
BFS using precomputed values+Path // Path Reconstruction
Reconstruction
cout << "Path: ";
int minMoves(int m, int n, char grid[100][100], int startX,
int startY, int goalX, int goalY) {
int px = goalX, py = goalY;
bool visited[100][100] = {false}; while (px != -1 && py != -1) {
int bfs_expansions = 0; // Track BFS expansions cout << "(" << px << "," << py << ") ";
Point prev = parent[px][py];
int furthestX[100][100][4], furthestY[100][100][4]; px = prev.x;
precompute(m, n, grid, furthestX, furthestY); py = prev.y;
}
Point queue[10000]; cout << endl;
int front = 0, rear = 0;
// Enqueue this intermediate cell if not visited. for (int i = 0; i < m; i++) {
if (!visited[tempX][tempY]) { for (int j = 0; j < n; j++) {
visited[tempX][tempY] = true; cin >> grid[i][j];
queue[rear++] = {tempX, tempY, }
current.moves + 1}; }
parent[tempX][tempY] = {current.x, current.y,
current.moves}; int startX, startY, goalX, goalY;
} cin >> startX >> startY >> goalX >> goalY;
// If we've reached the precomputed furthest cell, stop.
cout << minMoves(m, n, grid, startX, startY, goalX,
if (tempX == jumpX && tempY == jumpY)
goalY) << endl;
break;
return 0;
}
}
}
}
Shortest Path
Test Case
(0,0) (0,1) (0,2) (0,3) (0,4)
(0,0) start
(1,0)
(2,0)
(3,0)
(4,0)
goal
(5,0)
Precomputation Precomputing for node (0,0):
// Precompute the furthest reachable
Right: Moves right until (0,2), since (0,3) is an obstacle
position in each direction
→ Store (0,2)
void precompute(int m, int n, char
grid[100][100], int furthestX[100][100][4],
int furthestY[100][100][4]) { (0,0) (0,1) (0,2)
for (int i = 0; i < m; i++) { precompute for each node
for (int j = 0; j < n; j++) {
if (grid[i][j] == 'X') continue; ignore obstacles Left: Already at the leftmost boundary → Store (0,0)
for (int dirdir=0
= 0; dir < 4; dir++) {
int newX = i, newY = j; Down: Moves down until (2,0), since (3,0) is an
while (true) { obstacle → Store (2,0)
int nextX = newX + dx[dir];
int nextY = newY + dy[dir];
if (nextX < 0 || nextX >= m || (0,0) (1,0) (2,0)
nextY < 0 || nextY >= n || grid[nextX]
[nextY] == 'X') dx[0]=0 ; dy[0]=1
break; Up: Already at the top boundary → Store (0,0)
newX = nextX;
newY = nextY;
}
Enqueue (0,0) node into the queue:
blocked
1,0
1,0 1,1 1,2 1,3 1,4
(2,0,1)
(1,0,1)
2,0 2,1 2,2 2,3 2,4
(0,2,1)
(0,1,1)
3,0 3,1 3,2 3,3 3,4
(0,0,0) (Dequeued)
(1,0,1)
2,0 2,1 2,2 2,3 2,4
(0,2,1)
(0,1,1)
3,0 3,1 3,2 3,3 3,4
(0,1,1)
(0,0,0) Dequeued
(2,4,2)
(2,4,2)
(2,3,2)
(2,3,2)
(2,1,2) (2,1,2)
(2,2,2) (2,2,2)
(2,2,2)
(1,2,2) (1,2,2,) (1,2,2)
StartX: 0; StartY: 0
GoalX: 5; GoalY: 4
THANK YOU
NAME: P. RAVEENA
ECE-C