Solution: Minimum Cost to Make at Least One Valid Path in a Grid

Let’s solve the Minimum Cost to Make at Least One Valid Path in a Grid using the Graphs pattern.

Statement

You are given an m×nm \times n grid, where each cell contains a directional sign indicating which neighboring cell to move to next. The sign in a cell grid[i][j] can be:

  • 1: Move right, i.e., from grid[i][j] to grid[i][j + 1].

  • 2: Move left, i.e., from grid[i][j] to grid[i][j - 1].

  • 3: Move down, i.e., from grid[i][j] to grid[i + 1][j].

  • 4: Move up, i.e., from grid[i][j] to grid[i - 1][j].

Note: Some signs may point outside the boundaries of the grid.

Your starting position is the top-left cell (0,0)(0, 0). A valid path is any sequence of moves beginning at (0,0)(0,0) and ending at the bottom-right cell (m1,n1)(m - 1, n - 1), where each move follows the direction of the sign in the current cell.

You are allowed to change the direction of a sign in any cell, but each modification incurs a cost of 1, and each sign can be modified only once.

Your task is to determine the minimum total cost required to ensure that at least one valid path exists from the top left to the bottom right cell.

Constraints:

  • n==n == grid.length

  • m==m== grid[i].length

  • 1m,n501 \leq m, n \leq 50

  • 11 \leq grid[i][j] 4\leq 4

Solution

The core intuition behind this algorithm is to find the minimum cost required to create at least one valid path from the top-left to the bottom-right cell in a grid, where each cell initially directs movement in one of four directions (right, left, down, or up). To model this, we use a 2D array, costGrid, to store the minimum cost needed to reach each cell, initializing all values to infinity except the starting cell, which is set to zero. The algorithm explores all paths using 0-1 BFS with a deque, where moves that follow the current cell’s direction incur zero cost and are pushed to the front, while changes in direction incur a cost of one and are pushed to the back. This ensures that lower-cost paths are processed first, allowing the algorithm to find the minimum cost path efficiently. For every cell processed, we examine all four possible directions, calculate the movement cost, and update the costGrid if a cheaper cost is found. This way, the algorithm consistently prioritizes the most cost-effective paths, ultimately identifying the minimum-cost route that adheres to the grid's directional constraints.

Using the intuition above, we implement the algorithm as follows:

  1. Store the number of rows and columns of the grid in n and m, respectively.

  2. Create a 2D array, costGrid, of size n ×\times m, initializing all cells to the maximum integer value to represent infinite cost.

  3. Create a deque, dq, and push the starting cell (0, 0) to the front, setting its cost in costGrid to 0.

  4. Define an array, dirs, representing the four possible movement directions: right, left, down, and up.

  5. Enter a loop that continues as long as the dq is not empty:

    1. Pop the front cell from the dq and store its coordinates in row and col.

    2. Loop through each of the four directions in dirs using the index d:

      1. Use row, col, and dirs[d] to compute the adjacent cell coordinates as newRow and newCol.

      2. Using the helper function isValidAndImprovable, check if the new cell is valid and its cost can be improved. If so:

        1. Calculate the movement cost: if the current cell’s value matches d + 1, the cost is 0; otherwise, it’s 1.

        2. Check whether the new cost (costGrid[row][col] + cost) is less than the current cost at the adjacent cell (costGrid[newRow][newCol]).

          1. If it is, update the cost of the adjacent cell.

          2. Push the new cell to the back of the dq if the cost is 1 (less optimal); push it to the front if the cost is 0 (more optimal).

          3. If the cost is 1 (less optimal), push the new cell to the back of the dq; if it is 0 (more optimal), push it to the front.

  6. After processing all paths, return the minimum cost stored in the bottom-right cell costGrid[n - 1][m - 1].

The isValidAndImprovable helper function receives costGrid, row, and col, and returns TRUE if:

  • The row index is within the vertical bounds.

  • The col index is within the horizontal bounds.

  • The cost at (row, col) is not equal to 0, meaning the cell may still be improved.

Let’s look at the following illustration to get a better understanding of the solution:

Level up your interview prep. Join Educative to access 70+ hands-on prep courses.