Grade 12 · Grid algorithms: Lee and flood fillCitește în română

Lee: the shortest path in a grid

Original: Lee — drumul minim într-o grilă

O(n²)C++1782 lines2 examples

The idea

The grid has n rows and m columns: 0 = free, 1 = obstacle. We can move up, down, left, right. Lee's algorithm is a breadth-first search: d[xs][ys] = 1, then we take cells out of the queue in order of distance and give every free unvisited neighbour the value d + 1. The first time a cell receives a value, that value is minimal, because all cells at distance k are processed before those at distance k + 1. We print d[xf][yf], i.e. the number of cells on the path (including both ends), or -1 if there is no path.

Original description (Romanian)

Grila are n linii și m coloane: 0 = liber, 1 = obstacol. Ne putem deplasa sus, jos, stânga, dreapta. Algoritmul lui Lee este o parcurgere în lățime: d[xs][ys] = 1, apoi scoatem celulele din coadă în ordinea distanței și dăm fiecărui vecin liber nevizitat valoarea d + 1. Prima dată când o celulă primește o valoare, aceasta este minimă, pentru că toate celulele de la distanța k sunt prelucrate înaintea celor de la distanța k + 1. Afișăm d[xf][yf], adică numărul de celule ale drumului (inclusiv capetele), sau -1 dacă nu există drum.

Complexity
O(n * m)
Grade
Grade 12 (Clasa a XII-a)

Examples

Example 1

Input

5 5
0 0 0 1 0
1 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
1 1 5 5

Expected output

9
Example 2

Input

3 3
0 1 0
1 1 0
0 0 0
1 1 3 3

Expected output

-1

The code

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

lee-drumul-minim.cpp
/*
 * Titlu: Lee — drumul minim într-o grilă
 * Clasa: 12
 * Capitol: Algoritmi pe grile: Lee și fill
 * Descriere: Grila are n linii și m coloane: 0 = liber, 1 = obstacol. Ne putem
 *            deplasa sus, jos, stânga, dreapta. Algoritmul lui Lee este o
 *            parcurgere în lățime: d[xs][ys] = 1, apoi scoatem celulele din coadă
 *            în ordinea distanței și dăm fiecărui vecin liber nevizitat valoarea
 *            d + 1. Prima dată când o celulă primește o valoare, aceasta este
 *            minimă, pentru că toate celulele de la distanța k sunt prelucrate
 *            înaintea celor de la distanța k + 1. Afișăm d[xf][yf], adică numărul
 *            de celule ale drumului (inclusiv capetele), sau -1 dacă nu există drum.
 * Complexitate: O(n * m)
 *
 * Exemplu
 * Intrare:
 * 5 5
 * 0 0 0 1 0
 * 1 1 0 1 0
 * 0 0 0 0 0
 * 0 1 1 1 0
 * 0 0 0 1 0
 * 1 1 5 5
 * Ieșire: 9
 *
 * Exemplu
 * Intrare:
 * 3 3
 * 0 1 0
 * 1 1 0
 * 0 0 0
 * 1 1 3 3
 * Ieșire: -1
 */
#include <iostream>
#include <queue>
#include <utility>
using namespace std;

const int DIM = 1002;
int d[DIM][DIM]; // -1 = obstacol sau bordură, 0 = nevizitat, k > 0 = distanța
int dl[4] = {-1, 0, 1, 0};
int dc[4] = {0, 1, 0, -1};

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 0; i <= n + 1; i++)
        for (int j = 0; j <= m + 1; j++)
            d[i][j] = -1; // bordura
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            int x;
            cin >> x;
            d[i][j] = (x == 1 ? -1 : 0);
        }
    int xs, ys, xf, yf;
    cin >> xs >> ys >> xf >> yf;

    queue<pair<int, int>> q;
    d[xs][ys] = 1;
    q.push({xs, ys});
    while (!q.empty() && d[xf][yf] == 0)
    {
        int l = q.front().first, c = q.front().second;
        q.pop();
        for (int k = 0; k < 4; k++)
        {
            int lv = l + dl[k], cv = c + dc[k];
            if (d[lv][cv] == 0)
            {
                d[lv][cv] = d[l][c] + 1;
                q.push({lv, cv});
            }
        }
    }
    cout << (d[xf][yf] > 0 ? d[xf][yf] : -1) << '\n';
    return 0;
}

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