Open In App

Optimal Path in Matrix

Given a matrix grid[][] of size M * N, where grid[i][j] represents the value of the cell at position (i, j), the task is to determine an optimal path from the top-left corner to the bottom-right corner while minimizing the maximum value of |grid[i1][j1] – grid[i2][j2]| for adjacent cells along the path.

Example:



Input: {{2,2,2},
{2,8,4},
{1,2,2}};
Output: 1
Explanation: The optimal path is {2, 2, 1, 2, 2}, the maximum absolute difference of adjacent cells here is 1.

Input: {{3,2,2},
{7,1,8},
{1,1,3}};
Output: 2
Explanation: The optimal path is {3, 2, 1, 1, 3}, the maximum absolute difference of adjacent cells here is 2.



Optimal Path in Matrix using Binary Search + DFS:

We can use Binary Search to find the optimal path. Initialize a search space [low, high] to [0, INT_MAX] where our answer could possible. Now check for mid of this range is valid answer or not (here, we have to check that absolute difference of adjacent cell should not be more than mid.), if valid then move the high to mid – 1, otherwise move start to mid + 1.

Step-by-step approach:

Below is the implementation of the above approach:




// C++ code to implement the above approach
 
#include <bits/stdc++.h>
using namespace std;
int M, N;
 
// Function to check if there is a valid path
bool isValid(int i, int j, int x,
             vector<vector<bool> >& visited,
             vector<vector<int> >& grid, long long parent)
{
    // Check if we go outside the matrix or
    // cell(i, j) is visited or absolute
    // difference between consective cell
    // is greater then our assumed maximum
    // value required If true,
    // then return false
    if (i < 0 || j < 0 || i >= M || j >= N || visited[i][j]
        || abs((long long)grid[i][j] - parent) > x)
        return false;
 
    // Check if we reach at bottom-right
    // cell If true, then return true
    if (i == M - 1 && j == N - 1)
        return true;
 
    // Make the current cell(i, j) visited
    visited[i][j] = true;
 
    // Make all four direction call and
    // check if any path is valid If true,
    // then return true.
    if (isValid(i + 1, j, x, visited, grid, grid[i][j]))
        return true;
    if (isValid(i - 1, j, x, visited, grid, grid[i][j]))
        return true;
    if (isValid(i, j + 1, x, visited, grid, grid[i][j]))
        return true;
    if (isValid(i, j - 1, x, visited, grid, grid[i][j]))
        return true;
 
    // Otherwise, return false
    return false;
}
 
// Function to find the minimum value among
// the maximum adjacent differences
int optimalPath(vector<vector<int> >& grid)
{
    // Initialize a variable low = 0
    // and high = maximum possible
    // value required
    int low = 0, high = 10000000;
 
    // Initailize a variable result
    int result = grid[0][0];
 
    // Loop to implement the binary search
    while (low <= high) {
        int mid = (low + high) / 2;
 
        // Initilize a visited array
        // of size (M * N)
        vector<vector<bool> > visited(
            M, vector<bool>(N, false));
 
        // Check if mid is valid
        // answer, by choosing any
        // path into the grid If true,
        // update the result and
        // move high to mid - 1
        if (isValid(0, 0, mid, visited, grid, grid[0][0])) {
 
            result = mid;
            high = mid - 1;
        }
 
        // Otherwise, move low to mid + 1
        else {
 
            low = mid + 1;
        }
    }
 
    // Return the result
    return result;
}
 
// Driver code
int main()
{
    vector<vector<int> > grid = {
        { 1, 2, 1 },
        { 2, 8, 2 },
        { 2, 4, 2 },
    };
    M = grid.size(), N = grid[0].size();
 
    // Function Call
    cout << optimalPath(grid);
 
    return 0;
}




import java.util.Arrays;
 
public class OptimalPath {
    // Class variable to store the size of the grid
    static int M, N;
 
    // Function to check if there is a valid path
    static boolean isValid(int i, int j, int x,
                            boolean[][] visited,
                            int[][] grid, long parent) {
        // Check if we go outside the matrix or
        // cell(i, j) is visited or absolute
        // difference between consecutive cell
        // is greater than our assumed maximum
        // value required. If true,
        // then return false
        if (i < 0 || j < 0 || i >= M || j >= N || visited[i][j]
                || Math.abs((long) grid[i][j] - parent) > x)
            return false;
 
        // Check if we reach at bottom-right
        // cell. If true, then return true
        if (i == M - 1 && j == N - 1)
            return true;
 
        // Make the current cell(i, j) visited
        visited[i][j] = true;
 
        // Make all four direction calls and
        // check if any path is valid. If true,
        // then return true.
        if (isValid(i + 1, j, x, visited, grid, grid[i][j]))
            return true;
        if (isValid(i - 1, j, x, visited, grid, grid[i][j]))
            return true;
        if (isValid(i, j + 1, x, visited, grid, grid[i][j]))
            return true;
        if (isValid(i, j - 1, x, visited, grid, grid[i][j]))
            return true;
 
        // Otherwise, return false
        return false;
    }
 
    // Function to find the minimum value among
    // the maximum adjacent differences
    static int optimalPath(int[][] grid) {
        // Initialize a variable low = 0
        // and high = maximum possible
        // value required
        int low = 0, high = 10000000;
 
        // Initialize a variable result
        int result = grid[0][0];
 
        // Loop to implement binary search
        while (low <= high) {
            int mid = (low + high) / 2;
 
            // Initialize a visited array
            // of size (M * N)
            boolean[][] visited = new boolean[M][N];
 
            // Check if mid is a valid
            // answer, by choosing any
            // path into the grid. If true,
            // update the result and
            // move high to mid - 1
            if (isValid(0, 0, mid, visited, grid, grid[0][0])) {
                result = mid;
                high = mid - 1;
            }
            // Otherwise, move low to mid + 1
            else {
                low = mid + 1;
            }
        }
 
        // Return the result
        return result;
    }
 
    // Driver code
    public static void main(String[] args) {
        int[][] grid = {
                {1, 2, 1},
                {2, 8, 2},
                {2, 4, 2},
        };
        M = grid.length;
        N = grid[0].length;
 
        // Function Call
        System.out.println(optimalPath(grid));
    }
}




M, N = 0, 0  # Global variables to store the dimensions of the grid
 
# Function to check if there is a valid path
def is_valid(i, j, x, visited, grid, parent):
    global M, N
 
    # Check if we go outside the matrix or
    # cell(i, j) is visited or absolute
    # difference between consecutive cell
    # is greater than our assumed maximum
    # value required. If true, then return false.
    if i < 0 or j < 0 or i >= M or j >= N or visited[i][j] or abs(grid[i][j] - parent) > x:
        return False
 
    # Check if we reach the bottom-right cell. If true, then return true.
    if i == M - 1 and j == N - 1:
        return True
 
    # Make the current cell(i, j) visited
    visited[i][j] = True
 
    # Make all four direction calls and
    # check if any path is valid. If true,
    # then return true.
    if is_valid(i + 1, j, x, visited, grid, grid[i][j]):
        return True
    if is_valid(i - 1, j, x, visited, grid, grid[i][j]):
        return True
    if is_valid(i, j + 1, x, visited, grid, grid[i][j]):
        return True
    if is_valid(i, j - 1, x, visited, grid, grid[i][j]):
        return True
 
    # Otherwise, return false
    return False
 
# Function to find the minimum value among
# the maximum adjacent differences
def optimal_path(grid):
    global M, N
 
    # Initialize variables low = 0
    # and high = maximum possible
    # value required
    low, high = 0, 10000000
 
    # Initialize a variable result
    result = grid[0][0]
 
    # Loop to implement binary search
    while low <= high:
        mid = (low + high) // 2
 
        # Initialize a visited array
        # of size (M * N)
        visited = [[False for _ in range(N)] for _ in range(M)]
 
        # Check if mid is a valid answer, by choosing any
        # path into the grid. If true, update the result and
        # move high to mid - 1.
        if is_valid(0, 0, mid, visited, grid, grid[0][0]):
            result = mid
            high = mid - 1
        # Otherwise, move low to mid + 1.
        else:
            low = mid + 1
 
    # Return the result
    return result
 
# Driver code
if __name__ == "__main__":
    grid = [
        [1, 2, 1],
        [2, 8, 2],
        [2, 4, 2]
    ]
    M, N = len(grid), len(grid[0])
 
    # Function Call
    print(optimal_path(grid))




// C# code to implement the above approach
using System;
using System.Collections.Generic;
 
public class GFG {
    static int M, N;
 
    // Function to check if there is a valid path
    static bool IsValid(int i, int j, int x,
                        bool[, ] visited,
                        List<List<int> > grid, long parent)
    {
        // Check if we go outside the matrix or
        // cell(i, j) is visited or absolute
        // difference between consecutive cell
        // is greater than our assumed maximum
        // value required If true,
        // then return false
        if (i < 0 || j < 0 || i >= M || j >= N
            || visited[i, j]
            || Math.Abs(grid[i][j] - parent) > x)
            return false;
 
        // Check if we reach at bottom-right
        // cell If true, then return true
        if (i == M - 1 && j == N - 1)
            return true;
 
        // Make the current cell(i, j) visited
        visited[i, j] = true;
 
        // Make all four direction calls and
        // check if any path is valid. If true,
        // then return true.
        if (IsValid(i + 1, j, x, visited, grid, grid[i][j]))
            return true;
        if (IsValid(i - 1, j, x, visited, grid, grid[i][j]))
            return true;
        if (IsValid(i, j + 1, x, visited, grid, grid[i][j]))
            return true;
        if (IsValid(i, j - 1, x, visited, grid, grid[i][j]))
            return true;
 
        // Otherwise, return false
        return false;
    }
 
    // Function to find the minimum value among
    // the maximum adjacent differences
    static int OptimalPath(List<List<int> > grid)
    {
        // Initialize a variable low = 0
        // and high = maximum possible
        // value required
        int low = 0, high = 10000000;
 
        // Initialize a variable result
        int result = grid[0][0];
 
        // Loop to implement the binary search
        while (low <= high) {
            int mid = (low + high) / 2;
 
            // Initialize a visited array
            // of size (M * N)
            bool[, ] visited = new bool[M, N];
 
            // Check if mid is a valid
            // answer, by choosing any
            // path into the grid. If true,
            // update the result and
            // move high to mid - 1
            if (IsValid(0, 0, mid, visited, grid,
                        grid[0][0])) {
                result = mid;
                high = mid - 1;
            }
            // Otherwise, move low to mid + 1
            else {
                low = mid + 1;
            }
        }
 
        // Return the result
        return result;
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        List<List<int> > grid = new List<List<int> >{
            new List<int>{ 1, 2, 1 },
            new List<int>{ 2, 8, 2 },
            new List<int>{ 2, 4, 2 }
        };
        M = grid.Count;
        N = grid[0].Count;
 
        // Function Call
        Console.WriteLine(OptimalPath(grid));
    }
}




// JavaScript Implementation of the given problem
 
let M, N;
 
// Function to check if there is a valid path
function isValid(i, j, x, visited, grid, parent) {
    // Check if we go outside the matrix or cell(i, j) is visited
    // or absolute difference between consecutive cells is greater
    // than our assumed maximum value required. If true, return false.
    if (i < 0 || j < 0 || i >= M || j >= N ||
    visited[i][j] || Math.abs(grid[i][j] - parent) > x) {
        return false;
    }
 
    // Check if we reach the bottom-right
    // cell. If true, return true.
    if (i === M - 1 && j === N - 1) {
        return true;
    }
 
    // Make the current cell(i, j) visited
    visited[i][j] = true;
 
    // Make all four directional calls and
    // check if any path is valid. If true, return true.
    if (isValid(i + 1, j, x, visited, grid, grid[i][j])) return true;
    if (isValid(i - 1, j, x, visited, grid, grid[i][j])) return true;
    if (isValid(i, j + 1, x, visited, grid, grid[i][j])) return true;
    if (isValid(i, j - 1, x, visited, grid, grid[i][j])) return true;
 
    // Otherwise, return false
    return false;
}
 
// Function to find the minimum value
// among the maximum adjacent differences
function optimalPath(grid) {
    // Initialize variables low = 0 and
    // high = maximum possible value required
    let low = 0,
    high = 10000000;
 
    // Initialize a variable result
    let result = grid[0][0];
 
    // Loop to implement the binary search
    while (low <= high) {
        let mid = Math.floor((low + high) / 2);
 
        // Initialize a visited array of size (M * N)
        let visited = new Array(M).fill(false).map(() => new Array(N).fill(false));
 
        // Check if mid is a valid answer by choosing
        // any path into the grid
        // If true, update the result and move high to mid - 1
        if (isValid(0, 0, mid, visited, grid, grid[0][0])) {
            result = mid;
            high = mid - 1;
        }
        else {
            // Otherwise, move low to mid + 1
            low = mid + 1;
        }
    }
 
    // Return the result
    return result;
}
 
// Driver code
 
const grid = [
    [1, 2, 1],
    [2, 8, 2],
    [2, 4, 2],
];
M = grid.length;
N = grid[0].length;
 
// Function Call
console.log(optimalPath(grid));

Output
1








Time Complexity: O(log2(K) * (M*N)), where K is the maximum element in the matrix and M, and N are the number of rows and columns in the given matrix respectively.
Auxiliary Space: O(M * N)


Article Tags :