0% found this document useful (0 votes)
30 views18 pages

Castle On The Grid

The document outlines an approach to finding the shortest path in a grid using Breadth-First Search (BFS) with precomputation techniques. Precomputation allows for efficient storage of reachable positions, which speeds up queries significantly. The BFS implementation leverages precomputed values to minimize repeated calculations and improve performance.

Uploaded by

raveena1684
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views18 pages

Castle On The Grid

The document outlines an approach to finding the shortest path in a grid using Breadth-First Search (BFS) with precomputation techniques. Precomputation allows for efficient storage of reachable positions, which speeds up queries significantly. The BFS implementation leverages precomputed values to minimize repeated calculations and improve performance.

Uploaded by

raveena1684
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 18

Castle on the Grid (Finding the shortest path)

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.

Why Use Precomputation?


Reduces repeated BFS calls.
Speeds up queries (from O(V+E) to O(1) or O(log N))
#include<iostream>
using namespace std;
struct Point {
int x, y, moves;
};
(r-1,c)
int dx[] = {0, 0, 1, -1}; // Right, Left, Down, Up
int dy[] = {1, -1, 0, 0};
( (
c c
// To store parent positions for path reconstruction
+
Point parent[100][100];
1
- (r,c) 1
,r ,r
) )

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

queue[rear++] = {startX, startY, 0};


return current.moves;
visited[startX][startY] = true; }
parent[startX][startY] = {-1, -1, -1};
while (front < rear) { for (int i = 0; i < 4; i++) {
bfs_expansions++; // Increment counter // Use precomputed values: furthest reachable cell from
Point current = queue[front++]; current
int jumpX = furthestX[current.x][current.y][i];
if (current.x == goalX && current.y == goalY) { int jumpY = furthestY[current.x][current.y][i];
cout << "BFS Expansions: " << bfs_expansions // Now, traverse from current.x,current.y to (jumpX, jumpY)
<< endl; // Print expansions one step at a time along the same direction.
int tempX = current.x, tempY = current.y;
while (true) { cout << "BFS Expansions: " << bfs_expansions <<
int nextX = tempX + dx[i]; endl;
int nextY = tempY + dy[i]; return -1; // Return -1 if no path is found.
// Break if out-of-bounds or hit an obstacle }
if (nextX < 0 || nextX >= m || nextY < 0 || nextY
>= n || grid[nextX][nextY] == 'X') int main() {
break; int m, n;
tempX = nextX; cin >> m >> n;
tempY = nextY; char grid[100][100];

// 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

0,0 0,1 0,2 0,3 0,4

1,0 1,1 1,2 1,3 1,4

2,0 2,1 2,2 2,3 2,4

3,0 3,1 3,2 3,3 3,4


(0,0,0)

4,0 4,1 4,2 4,3 4,4

5,0 5,1 5,2 5,3 5,4


BFS Expansion=1, Dequeue(0,0,0)

Enqueue neighbours of (0,0) node into the queue:


0,0 0,1 0,2 0,3 0,4

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)

4,0 4,1 4,2 4,3 4,4

5,0 5,1 5,2 5,3 5,4


BFS Expansion=2, Dequeue(0,1,1)

Enqueue neighbours of (0,1) node into the queue:


0,0 0,1 0,2 0,3 0,4

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,1,1)
(0,0,0) Dequeued

4,0 4,1 4,2 4,3 4,4


Note: There are no unvisited neighbours of
(0,1,1)
5,0 5,1 5,2 5,3 5,4
BFS Expansion=3, Dequeue(0,2,1)
Enqueue neighbours of (0,2) node into the queue:

0,0 0,1 0,2 0,3 0,4

1,0 1,1 1,2 1,3 1,4


(2,2,2)

(1,2,2) 2,0 2,1 2,2 2,3 2,4


(2,0,1)

(1,0,1) 3,0 3,1 3,2 3,3 3,4


(0,2,1) Dequeued

(0,1,1) 4,0 4,1 4,2 4,3 4,4


(0,0,0)
5,0 5,1 5,2 5,3 5,4
BFS Expansion=4, Dequeue(1,0,1) BFS Expansion=5, Dequeue(2,0,1) BFS Expansion=6, Dequeue(1,2,2)

No unvisited neighbours found No unvisited neighbours found

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

(2,0,1) (2,0,1) (2,0,1)

(1,0,1) (1,0,1) (1,0,1)

(0,2,1) (0,2,1) (0,2,1)

(0,1,1) (0,1,1) (0,1,1)

(0,0,0) (0,0,0) (0,0,0)


Remaining BFS approach expansions:

BFS Expansion=7, Dequeue(2,2,2)


Queue:[ (2,1,2), (2,3,2), (2,4,2) ]

BFS Expansion=8, Dequeue(2,1,2)


Queue:[ (2,3,2), (2,4,2), (3,1,3), (4,1,3) ]

BFS Expansion=9, Dequeue(2,3,2)


Queue:[ (2,4,2), (3,1,3), (4,1,3), (3,3,3), (4,3,3), (5,3,3) ]

BFS Expansion=10, Dequeue(2,4,2)


Queue:[ (3,1,3), (4,1,3), (3,3,3), (4,3,3), (5,3,3), (1,4,3), (0,4,3) ]

BFS Expansion=11, Dequeue(3,1,3)


Queue:[ (4,1,3), (3,3,3), (4,3,3), (5,3,3), (1,4,3), (0,4,3) ]

BFS Expansion=12, Dequeue(4,1,3)


Queue:[ (3,3,3), (4,3,3), (5,3,3), (1,4,3), (0,4,3), (4,2,4), (4,4,4), (4,0,4) ]
BFS Expansion=13, Dequeue(3,3,3)
Queue:[ (4,3,3), (5,3,3), (1,4,3), (0,4,3), (4,2,4), (4,4,4), (4,0,4) ]

BFS Expansion=14, Dequeue(4,3,3)


Queue:[ (5,3,3), (1,4,3), (0,4,3), (4,2,4), (4,4,4), (4,0,4) ] BFS Expansion=19, Dequeue(4,4,4)
Queue:[ (4,0,4), (5,4,4) ]
BFS Expansion=15, Dequeue(5,3,3) BFS Expansion=20, Dequeue(4,0,4)
Queue:[ (1,4,3), (0,4,3), (4,2,4), (4,4,4), (4,0,4), (5,4,4) ] Queue:[ (5,4,4), (5,0,5) ]

BFS Expansion=16, Dequeue(1,4,3) BFS Expansion=21, Dequeue(5,4,4)


Queue:[ (0,4,3), (4,2,4), (4,4,4), (4,0,4), (5,4,4) ] Queue:[ (5,0,5) ]

BFS Expansion=17, Dequeue(0,4,3) Last Dequeued Point= (5,4,4)


Queue:[ (4,2,4), (4,4,4), (4,0,4), (5,4,4) ]
Point.x==goalx; Point.y==goaly;

BFS Expansion=18, Dequeue(4,2,4) END POSITION FOUND (GOAL)


Queue:[ (4,4,4), (4,0,4), (5,4,4) ]
Path Reconstruction: Retraced Path:

cout << "Path: ";


int px = goalX, py = goalY;
(5,4) (5,3) (2,3)
while (px != -1 && py != -1) {
cout << "(" << px << "," << py << ") ";
Point prev = parent[px][py];
px = prev.x;
py = prev.y; (0,0) (2,0)
}
cout << endl;
return current.moves; Final Path (Reversed Order for Correct Traversal):

(0,0)--> (2,0)--> (2,3)--> (5,3)--> (5,4)


Input for the TestCase Output for the TestCase

Number of rows in grid: 6


Number of columns in grid: 5 BFS Expansions: 21
Path: (5,4), (5,3), (2,3), (2,0), (0,0)
Grid Nodes Pattern: Moves: 4
...X.
.X.X.
.....
X.X.X
.....
.XX..

StartX: 0; StartY: 0
GoalX: 5; GoalY: 4
THANK YOU

NAME: P. RAVEENA

ROLL NO: 24ECB1A37

ECE-C

You might also like