Grade 11 · BacktrackingCitește în română

Paths in a maze

Original: Drumuri într-un labirint

ExponentialC++1773 lines1 example

The idea

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.

Original description (Romanian)

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.

Complexity
exponential (the number of paths can be very large)
Grade
Grade 11 (Clasa a XI-a)

Examples

Example 1

Input

3 3
0 0 0
0 1 0
0 0 0

Expected output

Drumuri: 2
Cel mai scurt: 5

The code

Comments are in Romanian, as in the original collection. Edit freely: you can reset at any time.

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;
}

Runs on a real g++ (C++17, -O2) through Compiler Explorer. Keep runs short; there's a time limit.