Cod sursa(job #3295270)

Utilizator Lex._.Lexi Guiman Lex._. Data 3 mai 2025 22:00:25
Problema Barbar Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.97 kb
#include <bits/stdc++.h>
#define NMAX 1000
#define inf 1000000000
using namespace std;

int r, c;
pair<int, int> poz_intrare, poz_iesire; //coordonatele punctului de plecare a barbarului si a iesirii din temnita

char a[NMAX][NMAX]; //matricea citita
int distanta[NMAX][NMAX]; //distanta de la fiecare celula la un dragon

int ox[4]={0, 1, 0, -1}; //vectorii de directie
int oy[4]={1, 0, -1, 0};

bool d_intrare_iesire(int val) //returneaza 1 daca se poate ajunge de la intrare la iesire trecand doar prin celule cu distante mai mari sau egale cu val si 0 daca nu se poate
{
    queue<pair<int, int>> coada; //vom folosi algoritmul lui lee pentru a determina daca se poate ajunge de la intrare le un punct din matrice
    array<array<bool, NMAX>, NMAX> poate_ajunge; //salvam 1 daca se poate ajunge la acea celula (trecand doar prin celule cu valori mai mari sau egale cu val) si 0 daca nu
    for(int i=0; i<r; i++) for(int j=0; j<r; j++) poate_ajunge[i][j]=0; //initializam matricea poate_ajunge cu 0

    poate_ajunge[poz_intrare.first][poz_intrare.second]=1;
    coada.push(poz_intrare);
    while(!coada.empty())
    {
        pair<int, int> poz=coada.front();
        coada.pop();
        for(int i=0; i<4; i++)
        {
            pair<int, int> nou={poz.first+ox[i], poz.second+oy[i]}; //vecinul lui poz
            if((nou.first>=0 && nou.first<r) && (nou.second>=0 && nou.second<c) && (a[nou.first][nou.second]!='*' && a[nou.first][nou.second]!='D')) //daca pozitia vecinului este in matrice si este o pozitie libera
            {
                if(distanta[nou.first][nou.second]>=val && poate_ajunge[nou.first][nou.second]==0) //daca celula are o valoare mai mare sau egala cu val si nu am parcurs-o pana acum
                {
                    poate_ajunge[nou.first][nou.second]=1; //salvam ca se poate ajunge la pozitie
                    coada.push(nou); //adaugam vecinul la coada
                }
            }
        }
    }
    return poate_ajunge[poz_iesire.first][poz_iesire.second];
}

int cautare_binara() //cauta binar cea mai mare distanta pentru care putem gasi un drum de la intrare la iesire format numai din valori mai mari sau egale cu acea distanta
{
    int st=0, dr=distanta[poz_intrare.first][poz_intrare.second], distanta_maxima=0; //capetele stanga si dreapta pentru cautarea binara si distanta maxima ceruta
    while(st<=dr)
    {
        int mij=st+(dr-st)/2;
        if(d_intrare_iesire(mij)==1) //daca se poate ajunge la iesire astfel incat toate celulele prin care se trece sa aiba distante mai mari sau egale cu mij
        {
            st=mij+1;
            distanta_maxima=mij;
        }
        else //daca nu
        {
            dr=mij-1;
        }
    }
    return distanta_maxima;
}

int main()
{
    ifstream cin("barbar.in");
    ofstream cout("barbar.out");
    cin >> r >> c;
    for(int i=0; i<r; i++) //initializam vectorul de distante cu infinit
        for(int j=0; j<c; j++)
            distanta[i][j]=inf;
    queue<pair<int, int>> coada; //coada pentru algoritmul lui lee
    for(int i=0; i<r; i++)
    {
        for(int j=0; j<c; j++)
        {
            cin >> a[i][j];
            if(a[i][j]=='I') //daca am gasit intrarea
            {
                poz_intrare={i, j}; //salvam pozitia intrarii
            }
            if(a[i][j]=='O') //daca am gasit iesirea
            {
                poz_iesire={i, j}; //salvam pozitia iesirii
            }
            if(a[i][j]=='D') //daca am gasit un dragon
            {
                coada.push({i, j}); //salvam pozitia dragonului in coada
                distanta[i][j]=0; //salvam distanta de la celula la dragon ca fiind 0
            }
        }
    }
    //vom folosi algoritmul lui lee pentru a afla distanta fiecarei celule de la cel mai apropiat dragon
    while(!coada.empty())
    {
        pair<int, int> poz=coada.front();
        coada.pop();
        for(int i=0; i<4; i++)
        {
            pair<int, int> nou={poz.first+ox[i], poz.second+oy[i]}; //vecinul lui poz
            if((nou.first>=0 && nou.first<r) && (nou.second>=0 && nou.second<c))
            {
                if(a[nou.first][nou.second]!='*' && distanta[nou.first][nou.second]==inf) //daca celula este goala nu am parcurs-o pana acum
                {
                    distanta[nou.first][nou.second]=1+distanta[poz.first][poz.second]; //salvam distanta de la dragon pana la celula
                    coada.push(nou); //adaugam vecinul la coada
                }
            }
        }
    }
    //vom cauta binar cea mai mare distanta pentru care putem gasi un drum de la intrare la iesire format numai din valori mai mari sau egale cu acea distanta
    int distanta_maxima=cautare_binara();
    if(distanta_maxima==0) //daca distanta maxima ajunge sa fie 0, inseamna ca nu este posibil sa se ajunga de la intrare la iesire, deci afisam -1
        cout << -1;
    else //altfel, afisam distanta maxima
        cout << distanta_maxima;

    return 0;
}