Clasa a XI-a · Programare dinamicăRead in English

Numărul de drumuri într-o grilă cu obstacole în C++

În engleză: Number of paths in a grid with obstacles

O(n²)C++1767 de linii2 exemple

Ideea

O grilă n × m are celule libere (0) și obstacole (1). Câte drumuri duc din (1, 1) în (n, m) dacă ne mișcăm doar la dreapta sau în jos și nu intrăm în obstacole? Într-o celulă liberă se ajunge de sus sau din stânga, deci nr[i][j] = nr[i-1][j] + nr[i][j-1], iar într-un obstacol nr[i][j] = 0. Pornim cu nr[1][1] = 1 (dacă celula e liberă). Spre deosebire de backtracking, nu enumerăm drumurile, ci doar le numărăm.

Descrierea în engleză

An n × m grid has free cells (0) and obstacles (1). How many paths lead from (1, 1) to (n, m) if we move only right or down and never enter obstacles? A free cell is reached from above or from the left, so nr[i][j] = nr[i-1][j] + nr[i][j-1], and on an obstacle nr[i][j] = 0. We start with nr[1][1] = 1 (if that cell is free). Unlike backtracking, we do not enumerate the paths, we only count them.

Complexitate
O(n · m) timp și memorie
Clasa
Clasa a XI-a (Grade 11)

Exemple

Exemplul 1

Intrare

3 4
0 0 0 0
0 1 0 0
0 0 0 0

Ieșire așteptată

4
Exemplul 2

Intrare

2 2
0 1
1 0

Ieșire așteptată

0

Codul C++

Codul complet, cu comentarii în română. Îl poți modifica liber și îl poți reseta oricând.

drumuri-in-grila-cu-obstacole.cpp
/*
 * Titlu: Numărul de drumuri într-o grilă cu obstacole
 * Clasa: 11
 * Capitol: Programare dinamică
 * Descriere: O grilă n × m are celule libere (0) și obstacole (1). Câte drumuri duc din
 *            (1, 1) în (n, m) dacă ne mișcăm doar la dreapta sau în jos și nu intrăm în
 *            obstacole? Într-o celulă liberă se ajunge de sus sau din stânga, deci
 *            nr[i][j] = nr[i-1][j] + nr[i][j-1], iar într-un obstacol nr[i][j] = 0.
 *            Pornim cu nr[1][1] = 1 (dacă celula e liberă). Spre deosebire de
 *            backtracking, nu enumerăm drumurile, ci doar le numărăm.
 * Complexitate: O(n · m) timp și memorie
 *
 * Exemplu
 * Intrare:
 * 3 4
 * 0 0 0 0
 * 0 1 0 0
 * 0 0 0 0
 * Ieșire: 4
 *
 * Exemplu
 * Intrare:
 * 2 2
 * 0 1
 * 1 0
 * Ieșire: 0
 */
#include <iostream>
using namespace std;

int a[105][105];
long long nr[105][105];

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
        }
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i][j] == 1)
            {
                nr[i][j] = 0;
            }
            else if (i == 1 && j == 1)
            {
                nr[i][j] = 1;
            }
            else
            {
                nr[i][j] = nr[i - 1][j] + nr[i][j - 1];
            }
        }
    }
    cout << nr[n][m] << '\n';
    return 0;
}

Rulează pe un g++ adevărat (C++17, -O2) prin Compiler Explorer. Programele trebuie să se termine repede: există o limită de timp.