Longest Possible Route in a Matrix with Hurdles
Given an 2D binary matrix mat[][], where some cells are hurdles (denoted by 0
) and the rest are free cells (denoted by 1
), your task is to find the length of the longest possible route from a source cell (xs, ys)
to a destination cell (xd, yd)
.
- You may only move to adjacent cells (up, down, left, right).
- Diagonal moves are not allowed.
- A cell once visited in a path cannot be revisited in that same path.
- If it is impossible to reach the destination, return
-1
.
Examples:
Input: xs = 0, ys = 0, xd = 1, yd = 7
mat[][] = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ]
Output: 24
Explanation:
Input: xs = 0, ys = 3, xd = 2, yd = 2
mat[][] =[ [1, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 1, 1, 0, 0] ]
Output: -1
Explanation:
We can see that it is impossible to
reach the cell (2,2) from (0,3).
Table of Content
[Approach] Using Backtracking with Visited Matrix
The idea is to use Backtracking. We start from the source cell of the matrix, move forward in all four allowed directions, and recursively checks if they lead to the solution or not. If the destination is found, we update the value of the longest path else if none of the above solutions work we return false from our function.
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;
// Function to find the longest path using backtracking
int dfs(vector<vector<int>> &mat,
vector<vector<bool>> &visited, int i,
int j, int x, int y) {
int m = mat.size();
int n = mat[0].size();
// If destination is reached
if (i == x && j == y) {
return 0;
}
// If cell is invalid, blocked, or already visited
if (i < 0 || i >= m || j < 0 || j >= n ||
mat[i][j] == 0 || visited[i][j]) {
return -1;
}
// Mark current cell as visited
visited[i][j] = true;
int maxPath = -1;
// Four possible moves: up, down, left, right
int row[] = {-1, 1, 0, 0};
int col[] = {0, 0, -1, 1};
for (int k = 0; k < 4; k++) {
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, visited,
ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1) {
maxPath = max(maxPath, 1 + pathLength);
}
}
// Backtrack - unmark current cell
visited[i][j] = false;
return maxPath;
}
int findLongestPath(vector<vector<int>> &mat,
int xs, int ys, int xd, int yd) {
int m = mat.size();
int n = mat[0].size();
// Check if source or destination is blocked
if (mat[xs][ys] == 0 || mat[xd][yd] == 0) {
return -1;
}
vector<vector<bool>> visited(m, vector<bool>(n, false));
return dfs(mat, visited, xs, ys, xd, yd);
}
int main() {
vector<vector<int>> mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = findLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
cout << result << endl;
else
cout << -1 << endl;
return 0;
}
import java.util.Arrays;
public class GFG {
// Function to find the longest path using backtracking
public static int dfs(int[][] mat, boolean[][] visited,
int i, int j, int x, int y) {
int m = mat.length;
int n = mat[0].length;
// If destination is reached
if (i == x && j == y) {
return 0;
}
// If cell is invalid, blocked, or already visited
if (i < 0 || i >= m || j < 0 || j >= n || mat[i][j] == 0 || visited[i][j]) {
return -1; // Invalid path
}
// Mark current cell as visited
visited[i][j] = true;
int maxPath = -1;
// Four possible moves: up, down, left, right
int[] row = {-1, 1, 0, 0};
int[] col = {0, 0, -1, 1};
for (int k = 0; k < 4; k++) {
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, visited, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1) {
maxPath = Math.max(maxPath, 1 + pathLength);
}
}
// Backtrack - unmark current cell
visited[i][j] = false;
return maxPath;
}
public static int findLongestPath(int[][] mat, int xs, int ys, int xd, int yd) {
int m = mat.length;
int n = mat[0].length;
// Check if source or destination is blocked
if (mat[xs][ys] == 0 || mat[xd][yd] == 0) {
return -1;
}
boolean[][] visited = new boolean[m][n];
return dfs(mat, visited, xs, ys, xd, yd);
}
public static void main(String[] args) {
int[][] mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = findLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
System.out.println(result);
else
System.out.println(-1);
}
}
# Function to find the longest path using backtracking
def dfs(mat, visited, i, j, x, y):
m = len(mat)
n = len(mat[0])
# If destination is reached
if i == x and j == y:
return 0
# If cell is invalid, blocked, or already visited
if i < 0 or i >= m or j < 0 or j >= n or mat[i][j] == 0 or visited[i][j]:
return -1 # Invalid path
# Mark current cell as visited
visited[i][j] = True
maxPath = -1
# Four possible moves: up, down, left, right
row = [-1, 1, 0, 0]
col = [0, 0, -1, 1]
for k in range(4):
ni = i + row[k]
nj = j + col[k]
pathLength = dfs(mat, visited, ni, nj, x, y)
# If a valid path is found from this direction
if pathLength != -1:
maxPath = max(maxPath, 1 + pathLength)
# Backtrack - unmark current cell
visited[i][j] = False
return maxPath
def findLongestPath(mat, xs, ys, xd, yd):
m = len(mat)
n = len(mat[0])
# Check if source or destination is blocked
if mat[xs][ys] == 0 or mat[xd][yd] == 0:
return -1
visited = [[False for _ in range(n)] for _ in range(m)]
return dfs(mat, visited, xs, ys, xd, yd)
def main():
mat = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
xs, ys = 0, 0
xd, yd = 1, 7
result = findLongestPath(mat, xs, ys, xd, yd)
if result != -1:
print(result)
else:
print(-1)
if __name__ == "__main__":
main()
using System;
class GFG
{
// Function to find the longest path using backtracking
static int dfs(int[,] mat, bool[,] visited,
int i, int j, int x, int y)
{
int m = mat.GetLength(0);
int n = mat.GetLength(1);
// If destination is reached
if (i == x && j == y)
{
return 0;
}
// If cell is invalid, blocked, or already visited
if (i < 0 || i >= m || j < 0 || j >= n || mat[i, j] == 0 || visited[i, j])
{
return -1; // Invalid path
}
// Mark current cell as visited
visited[i, j] = true;
int maxPath = -1;
// Four possible moves: up, down, left, right
int[] row = {-1, 1, 0, 0};
int[] col = {0, 0, -1, 1};
for (int k = 0; k < 4; k++)
{
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, visited, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1)
{
maxPath = Math.Max(maxPath, 1 + pathLength);
}
}
// Backtrack - unmark current cell
visited[i, j] = false;
return maxPath;
}
static int FindLongestPath(int[,] mat, int xs, int ys, int xd, int yd)
{
int m = mat.GetLength(0);
int n = mat.GetLength(1);
// Check if source or destination is blocked
if (mat[xs, ys] == 0 || mat[xd, yd] == 0)
{
return -1;
}
bool[,] visited = new bool[m, n];
return dfs(mat, visited, xs, ys, xd, yd);
}
static void Main()
{
int[,] mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = FindLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
Console.WriteLine(result);
else
Console.WriteLine(-1);
}
}
// Function to find the longest path using backtracking
function dfs(mat, visited, i, j, x, y) {
const m = mat.length;
const n = mat[0].length;
// If destination is reached
if (i === x && j === y) {
return 0;
}
// If cell is invalid, blocked, or already visited
if (i < 0 || i >= m || j < 0 || j >= n ||
mat[i][j] === 0 || visited[i][j]) {
return -1;
}
// Mark current cell as visited
visited[i][j] = true;
let maxPath = -1;
// Four possible moves: up, down, left, right
const row = [-1, 1, 0, 0];
const col = [0, 0, -1, 1];
for (let k = 0; k < 4; k++) {
const ni = i + row[k];
const nj = j + col[k];
const pathLength = dfs(mat, visited,
ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength !== -1) {
maxPath = Math.max(maxPath, 1 + pathLength);
}
}
// Backtrack - unmark current cell
visited[i][j] = false;
return maxPath;
}
function findLongestPath(mat, xs, ys, xd, yd) {
const m = mat.length;
const n = mat[0].length;
// Check if source or destination is blocked
if (mat[xs][ys] === 0 || mat[xd][yd] === 0) {
return -1;
}
const visited = Array(m).fill().map(() => Array(n).fill(false));
return dfs(mat, visited, xs, ys, xd, yd);
}
const mat = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
const xs = 0, ys = 0;
const xd = 1, yd = 7;
const result = findLongestPath(mat, xs, ys, xd, yd);
if (result !== -1)
console.log(result);
else
console.log(-1);
Output
24
Time Complexity: O(4^(m*n)) For each cell in the m x n matrix, the algorithm explores up to four possible directions (up, down, left, right), leading to an exponential number of paths. In the worst case, it explores all possible paths resulting in a time complexity of 4^(m*n).
Auxiliary Space: O(m*n) The algorithm uses an m x n visited matrix to track visited cells and a recursion stack that can grow to a depth of m * n in the worst case (e.g., when exploring a path covering all cells). Thus, the auxiliary space is O(m*n).
[Optimized Approach] Without Using Extra Space
Instead of maintaining a separate visited matrix, we can reuse the input matrix to mark visited cells during the traversal. This saves extra space and still ensures we don’t revisit the same cell in a path.
Below is the step-by-step approach:
- Start from the source cell
(xs, ys)
. - At each step, explore all four possible directions (right, down, left, up).
- For each valid move:
- Check boundaries and ensure the cell has value
1
(free cell). - Mark the cell as visited by temporarily setting it to
0
. - Recurse into the next cell and increment the path length.
- Check boundaries and ensure the cell has value
- If the destination cell
(xd, yd)
is reached, compare the current path length with the maximum so far and update the answer. - Backtrack: restore the cell’s original value (
1
) before returning to allow other paths to explore it. - Continue exploring until all possible paths are visited.
- Return the maximum path length. If the destination is unreachable, return
-1
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;
// Function to find the longest path using backtracking without extra space
int dfs(vector<vector<int>> &mat, int i, int j, int x, int y) {
int m = mat.size();
int n = mat[0].size();
// If destination is reached
if (i == x && j == y) {
return 0;
}
// If cell is invalid or blocked (0 means blocked or visited)
if (i < 0 || i >= m || j < 0 || j >= n || mat[i][j] == 0) {
return -1;
}
// Mark current cell as visited by temporarily setting it to 0
mat[i][j] = 0;
int maxPath = -1;
// Four possible moves: up, down, left, right
int row[] = {-1, 1, 0, 0};
int col[] = {0, 0, -1, 1};
for (int k = 0; k < 4; k++) {
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1) {
maxPath = max(maxPath, 1 + pathLength);
}
}
// Backtrack - restore the cell's original value (1)
mat[i][j] = 1;
return maxPath;
}
int findLongestPath(vector<vector<int>> &mat, int xs, int ys, int xd, int yd) {
int m = mat.size();
int n = mat[0].size();
// Check if source or destination is blocked
if (mat[xs][ys] == 0 || mat[xd][yd] == 0) {
return -1;
}
return dfs(mat, xs, ys, xd, yd);
}
int main() {
vector<vector<int>> mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = findLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
cout << result << endl;
else
cout << -1 << endl;
return 0;
}
public class GFG {
// Function to find the longest path using backtracking without extra space
public static int dfs(int[][] mat, int i, int j, int x, int y) {
int m = mat.length;
int n = mat[0].length;
// If destination is reached
if (i == x && j == y) {
return 0;
}
// If cell is invalid or blocked (0 means blocked or visited)
if (i < 0 || i >= m || j < 0 || j >= n || mat[i][j] == 0) {
return -1;
}
// Mark current cell as visited by temporarily setting it to 0
mat[i][j] = 0;
int maxPath = -1;
// Four possible moves: up, down, left, right
int[] row = {-1, 1, 0, 0};
int[] col = {0, 0, -1, 1};
for (int k = 0; k < 4; k++) {
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1) {
maxPath = Math.max(maxPath, 1 + pathLength);
}
}
// Backtrack - restore the cell's original value (1)
mat[i][j] = 1;
return maxPath;
}
public static int findLongestPath(int[][] mat, int xs, int ys, int xd, int yd) {
int m = mat.length;
int n = mat[0].length;
// Check if source or destination is blocked
if (mat[xs][ys] == 0 || mat[xd][yd] == 0) {
return -1;
}
return dfs(mat, xs, ys, xd, yd);
}
public static void main(String[] args) {
int[][] mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = findLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
System.out.println(result);
else
System.out.println(-1);
}
}
# Function to find the longest path using backtracking without extra space
def dfs(mat, i, j, x, y):
m = len(mat)
n = len(mat[0])
# If destination is reached
if i == x and j == y:
return 0
# If cell is invalid or blocked (0 means blocked or visited)
if i < 0 or i >= m or j < 0 or j >= n or mat[i][j] == 0:
return -1
# Mark current cell as visited by temporarily setting it to 0
mat[i][j] = 0
maxPath = -1
# Four possible moves: up, down, left, right
row = [-1, 1, 0, 0]
col = [0, 0, -1, 1]
for k in range(4):
ni = i + row[k]
nj = j + col[k]
pathLength = dfs(mat, ni, nj, x, y)
# If a valid path is found from this direction
if pathLength != -1:
maxPath = max(maxPath, 1 + pathLength)
# Backtrack - restore the cell's original value (1)
mat[i][j] = 1
return maxPath
def findLongestPath(mat, xs, ys, xd, yd):
m = len(mat)
n = len(mat[0])
# Check if source or destination is blocked
if mat[xs][ys] == 0 or mat[xd][yd] == 0:
return -1
return dfs(mat, xs, ys, xd, yd)
def main():
mat = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
xs, ys = 0, 0
xd, yd = 1, 7
result = findLongestPath(mat, xs, ys, xd, yd)
if result != -1:
print(result)
else:
print(-1)
if __name__ == "__main__":
main()
using System;
class GFG
{
// Function to find the longest path using backtracking without extra space
static int dfs(int[,] mat, int i, int j, int x, int y)
{
int m = mat.GetLength(0);
int n = mat.GetLength(1);
// If destination is reached
if (i == x && j == y)
{
return 0;
}
// If cell is invalid or blocked (0 means blocked or visited)
if (i < 0 || i >= m || j < 0 || j >= n || mat[i, j] == 0)
{
return -1;
}
// Mark current cell as visited by temporarily setting it to 0
mat[i, j] = 0;
int maxPath = -1;
// Four possible moves: up, down, left, right
int[] row = {-1, 1, 0, 0};
int[] col = {0, 0, -1, 1};
for (int k = 0; k < 4; k++)
{
int ni = i + row[k];
int nj = j + col[k];
int pathLength = dfs(mat, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength != -1)
{
maxPath = Math.Max(maxPath, 1 + pathLength);
}
}
// Backtrack - restore the cell's original value (1)
mat[i, j] = 1;
return maxPath;
}
static int FindLongestPath(int[,] mat, int xs, int ys, int xd, int yd)
{
// Check if source or destination is blocked
if (mat[xs, ys] == 0 || mat[xd, yd] == 0)
{
return -1;
}
return dfs(mat, xs, ys, xd, yd);
}
static void Main()
{
int[,] mat = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
int xs = 0, ys = 0;
int xd = 1, yd = 7;
int result = FindLongestPath(mat, xs, ys, xd, yd);
if (result != -1)
Console.WriteLine(result);
else
Console.WriteLine(-1);
}
}
// Function to find the longest path using backtracking without extra space
function dfs(mat, i, j, x, y) {
const m = mat.length;
const n = mat[0].length;
// If destination is reached
if (i === x && j === y) {
return 0;
}
// If cell is invalid or blocked (0 means blocked or visited)
if (i < 0 || i >= m || j < 0 || j >= n || mat[i][j] === 0) {
return -1;
}
// Mark current cell as visited by temporarily setting it to 0
mat[i][j] = 0;
let maxPath = -1;
// Four possible moves: up, down, left, right
const row = [-1, 1, 0, 0];
const col = [0, 0, -1, 1];
for (let k = 0; k < 4; k++) {
const ni = i + row[k];
const nj = j + col[k];
const pathLength = dfs(mat, ni, nj, x, y);
// If a valid path is found from this direction
if (pathLength !== -1) {
maxPath = Math.max(maxPath, 1 + pathLength);
}
}
// Backtrack - restore the cell's original value (1)
mat[i][j] = 1;
return maxPath;
}
function findLongestPath(mat, xs, ys, xd, yd) {
const m = mat.length;
const n = mat[0].length;
// Check if source or destination is blocked
if (mat[xs][ys] === 0 || mat[xd][yd] === 0) {
return -1;
}
return dfs(mat, xs, ys, xd, yd);
}
const mat = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
const xs = 0, ys = 0;
const xd = 1, yd = 7;
const result = findLongestPath(mat, xs, ys, xd, yd);
if (result !== -1)
console.log(result);
else
console.log(-1);
Output
24
Time Complexity: O(4^(m*n)),The algorithm still explores up to four directions per cell in the m x n matrix, resulting in an exponential number of paths. The in-place modification does not affect the number of paths explored, so the time complexity remains 4^(m*n).
Auxiliary Space: O(m*n), While the visited matrix is eliminated by modifying the input matrix in-place, the recursion stack still requires O(m*n) space, as the maximum recursion depth can be m * n in the worst case (e.g., a path visiting all cells in a grid with mostly 1s).