Rezolvare completă PbInfo #700 Labir

Şoricelul Jerry este (pentru a câta oară ?) în labirint. Labirintul poate fi codificat ca o matrice cu n linii şi m coloane formată din n*m celule pătratice identice. Liniile se numerotează de la 1 la n, iar coloanele de la 1 la m. Labirintul este format din celule libere şi din celule ocupate de pereţii labirintului.

La momentul iniţial, Jerry se găseşte într-o anumită celulă liberă şi misiunea lui este să ajungă la destinaţie într-o altă celulă liberă precizată. Șoricelul se poate deplasa din celula curentă în oricare dintre cele patru celule cu care aceasta are în comun o latură şi nu poate ieşi în afara labirintului. Este posibil ca el să nu poată să ajungă de la poziţia iniţială la cea finală trecând doar prin celule libere. În această situație el este nevoit să sfărâme peretele în anumite celule. Jerry şi-a pregătit dinamită în acest scop, pentru că nu i se pare optim să roadă peretele cu dinţii.

Cerința

Cunoscând dimensiunile n şi m ale labirintului, coordonatele celulei de plecare şi ale celulei destinaţie, precum şi coordonatele celulelor ocupate de pereţi, să se determine numărul minim de celule ocupate, pe care Jerry trebuie să le dinamiteze pentru a putea să ajungă la destinaţie.

Date de intrare

Fişierul de intrare labir.in conţine pe prima linie două numere naturale n şi m separate printr-un spaţiu, reprezentând numărul de linii, respectiv numărul de coloane ale matricei care codifică labirintul.

Pe linia a doua se găsesc patru numere naturale xi yi xf yf separate prin câte un spaţiu, reprezentând poziţia de plecare, respectiv poziţia destinaţie.

Pe linia a treia se găseşte un număr natural k, reprezentând numărul de celule ocupate.

Pe fiecare dintre următoarele k linii se vor găsi câte două numere x şi y separate printr-un spaţiu, reprezentând linia şi coloana unei celule ocupate.

Date de ieșire

Pe prima linie a fişierului labir.out se va scrie un singur număr natural D, reprezentând numărul minim de celule pe care Jerry trebuie să le dinamiteze pentru a ajunge la destinaţie.

Restricții și precizări

  • 2 ≤ n, m ≤ 5000
  • 1 ≤ k ≤ 50 000
  • Se garantează că pentru toate testele există cel puţin n/2 linii şi/sau m/2 coloane formate numai din celule neocupate.
  • Pentru 30% dintre teste n,m ≤ 1000.

Exemplu

labir.in

7 8
1 1 7 8
6
2 1
1 2
3 1
6 7
6 8
6 2

labir.out

1

Explicație

Celulele ocupate au fost colorate în gri. Șoricelul pleacă din celula notată cu P și sosește în celula S. Pentru aceasta el dinamitează celula (1, 2) și ajunge în S dinamitând un număr minim D = 1, de celule ocupate.

Cum e corect?

cout < "As la info"; cout << "As la info"; cout >> "As la info";

Felicitări! Poți mai mult?

Avem sute de probleme pentru tine, fiecare cu explicații ușor de înțeles.

Greșit, dar nu-i bai!

Antrenează-te cu sutele de probleme pe care ți le-am pregătit. Îți explicăm fiecare problemă în parte.

Rezolvare

Iată rezolvarea de 100 de puncte pentru problema Labir:

// 100 puncte
// Constantin Galatan
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <deque>
#include <iomanip>
using namespace std;

#define INF 0x3f3f3f3f
#define mp make_pair
#define pb push_back
typedef pair<int, int> PI;
typedef vector<int> VI;

ifstream fin("labir.in");
ofstream fout("labir.out");

int k; // nr de puncte
VI x, y, sx, sy;
int N, M, n, m, xi, yi, xf, yf;
bool A[5001][5001];
//bool B[1000][1000];
VI c[5001];
deque<PI> Q;

template <class Cont>
void Write(Cont c)
{
    for ( typename Cont::iterator it = c.begin(); it != c.end(); ++it )
        fout << *it << ' ';
     fout << '\n';
}


void BF_0_1();

int main()
{
    fin >> N >> M >> xi >> yi >> xf >> yf;
    fin >> k;
    int a, b;

    sx.pb(xi), sx.pb(xf);
    sy.pb(yi), sy.pb(yf);
    n = max(n, max(xi, xf));
    m = max(m, max(yi, yf));
    for ( int i = 0; i < k; ++i )
    {
        fin >> a >> b;
        n = max(n, a); m = max(m, b);
        sx.pb(a), sy.pb(b);
    }
    bool x_la_limita = true, y_la_limita = true;
    if ( n < N )
        x_la_limita = false, n++;
    if ( m < M )
        y_la_limita = false, m++;

    x.pb(0), y.pb(0);
    for ( size_t i = 0; i < sx.size(); ++i )
    {
        x.pb(sx[i] - 1), x.pb(sx[i]); // sa ramana cate o linie libera sau coloana
        y.pb(sy[i] - 1), y.pb(sy[i]);
    }

    sort(x.begin(), x.end());
    sort(y.begin(), y.end());

    x.erase(unique(x.begin(), x.end()), x.end());
    y.erase(unique(y.begin(), y.end()), y.end());
  //  Write(x); Write(y);

    n = 0, m = 0; int X, Y;
    for (size_t i = 0; i < sx.size(); ++i )
    {
        X = lower_bound(x.begin(), x.end(), sx[i]) - x.begin();
        Y = lower_bound(y.begin(), y.end(), sy[i]) - y.begin();
        n = max(n, X), m = max(m, Y);
        A[X][Y] = 1;
    }

    xi = lower_bound(x.begin(), x.end(), xi) - x.begin();
    xf = lower_bound(x.begin(), x.end(), xf) - x.begin();
    yi = lower_bound(y.begin(), y.end(), yi) - y.begin();
    yf = lower_bound(y.begin(), y.end(), yf) - y.begin();
    A[xi][yi] = A[xf][yf] = 0;
    if  (!x_la_limita)
        n++;
    if ( !y_la_limita )
        m++;
    for (int i = 1; i <= n; ++i )
        c[i].resize(m + 1, INF);

    BF_0_1();
    fout << c[xf][yf] << '\n';
    fin.close();
    fout.close();
    return 0;
}

bool Inside(int i, int j)
{
    return i >= 1 and i <= n and j >= 1 and j <= m;
}

const int di[] = { -1, 0, 1, 0},
          dj[] = { 0, 1, 0, -1 };

void BF_0_1()
{
    int iv, jv, i, j;
    PI pi;
    c[xi][yi] = A[xi][yi];
    Q.pb(mp(xi, yi));
    while ( !Q.empty() )
    {
        pi = Q.front(); Q.pop_front();
        i = pi.first, j = pi.second;
        for (int d = 0; d < 4; ++d )
        {
            iv = i + di[d], jv = j + dj[d];
            if ( Inside(iv, jv) and c[iv][jv] > c[i][j] + A[iv][jv])
            {
                c[iv][jv] = c[i][j] + A[i][j];
                if ( A[iv][jv] == 0 )
                    Q.push_front(mp(iv, jv));
                else
                    Q.push_back(mp(iv, jv));
            }
        }
    }
}

Atenție

Enunțurile afișate pe această pagină aparțin exclusiv site-ului PbInfo. Astfel, pentru ștergerea conținutului, puteți să ne contactați la adresa Adresa de email.

Rezolvarea problemei #700 Labir

Pe această pagină găsești rezolvarea de 100 de puncte pentru problema #700 Labir de pe PbInfo.ro. Atenție: nu încurajăm copiatul codului! Totuși, credem cu tărie că analizarea unei soluții corecte este o metodă foarte ușoară de a învăța informatică, astfel că oferim sursele pentru peste 1500 de probleme de pe platforma PbInfo.ro.

Pentru rezolvări PbInfo de la peste 1500 de probleme, vă invităm să intrați pe site-ul nostru!