Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Dynamic Programming for Grid Path Counting with and without Obstacles

Notes Jul 13 2

The classic problem of counting distinct paths in a rectangular grid where movement is restricted to right and down steps can be modeled as a binary tree structure, but such an approach leads to exponential time complexity. A more efficient solution uses dynamic programming with a two-dimensional state table.

Grid without Obstacles

Given an m x n grid, define ways[r][c] as the number of unique routes from the top-left corner (0,0) to cell (r,c). The recurrence relies on the fact that the only way to reach (r,c) is from the cell directly above or from the left:

ways[r][c] = ways[r-1][c] + ways[r][c-1]

For the first row and first column, only one straight-line path exists, so these cells are initialized to 1. The entire table is then filled row by row. The final answer resides at ways[m-1][n-1].

int countPaths(int rows, int cols) {
    vector<vector<int>> ways(rows, vector<int>(cols, 0));
    for (int r = 0; r < rows; ++r) ways[r][0] = 1;
    for (int c = 0; c < cols; ++c) ways[0][c] = 1;
    for (int r = 1; r < rows; ++r) {
        for (int c = 1; c < cols; ++c) {
            ways[r][c] = ways[r-1][c] + ways[r][c-1];
        }
    }
    return ways[rows-1][cols-1];
}

Grid with Obstacles

When some cells are blocked, they cannot be used in any path. The obstacle matrix grid contains 1 for blocked cells and 0 for free cells. The recurrence remains the same, but it applies only when the current cell is free; otherwise, the number of routes to that cell stays 0.

Initialization also changes. If a cell in the first row or first column is blocked, all cells beyond it in that row or column become unreachable and must remain 0.

int countPathsWithObstacles(vector<vector<int>>& grid) {
    int rows = grid.size();
    int cols = grid[0].size();
    
    if (grid[0][0] == 1 || grid[rows-1][cols-1] == 1) return 0;

    vector<vector<int>> ways(rows, vector<int>(cols, 0));
    for (int r = 0; r < rows && grid[r][0] == 0; ++r) ways[r][0] = 1;
    for (int c = 0; c < cols && grid[0][c] == 0; ++c) ways[0][c] = 1;

    for (int r = 1; r < rows; ++r) {
        for (int c = 1; c < cols; ++c) {
            if (grid[r][c] == 1) continue;
            ways[r][c] = ways[r-1][c] + ways[r][c-1];
        }
    }
    return ways[rows-1][cols-1];
}

The traversal order (top-to-bottom, left-to-right) ensures that the reuqired previous states have already been computed. For large grids, space can be optimized to a single row of size n, but the two-dimensional formulation clearly reflects the problem's structure.

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.