Clasa a XI-a · Metoda backtrackingRead in English

Drumuri într-un labirint în C++

În engleză: Paths in a maze

ExponențialăC++1773 de linii1 exemplu

Ideea

Labirintul este o matrice n × m cu 0 (liber) și 1 (zid). Pornim din colțul stânga-sus (1, 1) și vrem să ajungem în colțul dreapta-jos (n, m), mergând sus, jos, stânga sau dreapta, fără să trecem de două ori prin aceeași celulă. Din fiecare celulă încercăm cele 4 direcții; marcăm celula ca vizitată la intrare și o demarcăm la întoarcere. Se afișează numărul de drumuri și lungimea celui mai scurt (în celule), sau 0 dacă nu există drum.

Descrierea în engleză

The maze is an n × m matrix of 0 (free) and 1 (wall). We start in the top-left corner (1, 1) and want to reach the bottom-right corner (n, m), moving up, down, left or right, without passing through the same cell twice. From every cell we try the 4 directions; we mark the cell as visited on the way in and unmark it on the way back. The number of paths and the length of the shortest one (in cells) are printed, or 0 if there is no path.

Complexitate
exponențială (numărul de drumuri poate fi foarte mare)
Clasa
Clasa a XI-a (Grade 11)

Exemple

Exemplul 1

Intrare

3 3
0 0 0
0 1 0
0 0 0

Ieșire așteptată

Drumuri: 2
Cel mai scurt: 5

Codul C++

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

drumuri-in-labirint.cpp
/*
 * Titlu: Drumuri într-un labirint
 * Clasa: 11
 * Capitol: Metoda backtracking
 * Descriere: Labirintul este o matrice n × m cu 0 (liber) și 1 (zid). Pornim din colțul
 *            stânga-sus (1, 1) și vrem să ajungem în colțul dreapta-jos (n, m), mergând
 *            sus, jos, stânga sau dreapta, fără să trecem de două ori prin aceeași celulă.
 *            Din fiecare celulă încercăm cele 4 direcții; marcăm celula ca vizitată la
 *            intrare și o demarcăm la întoarcere. Se afișează numărul de drumuri și
 *            lungimea celui mai scurt (în celule), sau 0 dacă nu există drum.
 * Complexitate: exponențială (numărul de drumuri poate fi foarte mare)
 *
 * Exemplu
 * Intrare:
 * 3 3
 * 0 0 0
 * 0 1 0
 * 0 0 0
 * Ieșire:
 * Drumuri: 2
 * Cel mai scurt: 5
 */
#include <iostream>
using namespace std;

int n, m, a[12][12], drumuri = 0, minim = 1000;
bool vizitat[12][12];
int dl[4] = {-1, 0, 1, 0};
int dc[4] = {0, 1, 0, -1};

void back(int l, int c, int lungime)
{
    if (l == n && c == m)
    {
        drumuri++;
        if (lungime < minim)
        {
            minim = lungime;
        }
        return;
    }
    for (int d = 0; d < 4; d++)
    {
        int nl = l + dl[d], nc = c + dc[d];
        if (nl >= 1 && nl <= n && nc >= 1 && nc <= m && a[nl][nc] == 0 && !vizitat[nl][nc])
        {
            vizitat[nl][nc] = true;
            back(nl, nc, lungime + 1);
            vizitat[nl][nc] = false;
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
        }
    }
    if (a[1][1] == 0)
    {
        vizitat[1][1] = true;
        back(1, 1, 1);
    }
    cout << "Drumuri: " << drumuri << '\n';
    cout << "Cel mai scurt: " << (drumuri > 0 ? minim : 0) << '\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.