Clasa a XII-a · Algoritmi pe grile: Lee și fillRead in English

Fill — numărul de zone în C++

În engleză: Flood fill: the number of regions

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

Ideea

Matricea are n linii și m coloane, cu 1 pentru teren și 0 pentru apă. O zonă este un grup maxim de celule 1 legate prin laturi (sus, jos, stânga, dreapta). Parcurgem matricea; la prima celulă 1 nevizitată dintr-o zonă numărăm o zonă nouă și pornim „umplerea”: funcția recursivă fill marchează celula cu 0 și se apelează pentru cei 4 vecini. Bordăm matricea cu 0, ca să nu ieșim din ea. Fiecare celulă este marcată o singură dată.

Descrierea în engleză

The matrix has n rows and m columns, with 1 for land and 0 for water. A region is a maximal group of 1 cells connected through their sides (up, down, left, right). We walk the matrix; at the first unvisited 1 cell of a region we count a new region and start 'filling': the recursive function fill marks the cell with 0 and calls itself for the 4 neighbours. We border the matrix with 0s so we never step outside it. Every cell is marked only once.

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

Exemple

Exemplul 1

Intrare

4 5
1 1 0 0 1
1 0 0 1 1
0 0 1 0 0
1 0 1 1 0

Ieșire așteptată

4
Exemplul 2

Intrare

2 2
0 0
0 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.

fill-numarul-de-zone.cpp
/*
 * Titlu: Fill — numărul de zone
 * Clasa: 12
 * Capitol: Algoritmi pe grile: Lee și fill
 * Descriere: Matricea are n linii și m coloane, cu 1 pentru teren și 0 pentru apă.
 *            O zonă este un grup maxim de celule 1 legate prin laturi (sus, jos,
 *            stânga, dreapta). Parcurgem matricea; la prima celulă 1 nevizitată
 *            dintr-o zonă numărăm o zonă nouă și pornim „umplerea”: funcția
 *            recursivă fill marchează celula cu 0 și se apelează pentru cei 4
 *            vecini. Bordăm matricea cu 0, ca să nu ieșim din ea. Fiecare celulă
 *            este marcată o singură dată.
 * Complexitate: O(n * m)
 *
 * Exemplu
 * Intrare:
 * 4 5
 * 1 1 0 0 1
 * 1 0 0 1 1
 * 0 0 1 0 0
 * 1 0 1 1 0
 * Ieșire: 4
 *
 * Exemplu
 * Intrare:
 * 2 2
 * 0 0
 * 0 0
 * Ieșire: 0
 */
#include <iostream>
using namespace std;

const int DIM = 102;          // n, m <= 100, plus bordura
int a[DIM][DIM];
int dl[4] = {-1, 0, 1, 0};    // deplasările pe linie: sus, dreapta, jos, stânga
int dc[4] = {0, 1, 0, -1};    // deplasările pe coloană

void fill(int i, int j)
{
    a[i][j] = 0; // marcăm celula ca vizitată
    for (int d = 0; d < 4; d++)
    {
        int iv = i + dl[d], jv = j + dc[d];
        if (a[iv][jv] == 1)
            fill(iv, jv);
    }
}

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];
    // Liniile 0 și n + 1, coloanele 0 și m + 1 rămân 0 (variabilă globală): bordura.
    int zone = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (a[i][j] == 1)
            {
                zone++;
                fill(i, j);
            }
    cout << zone << '\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.