Cod sursa(job #3295272)

Utilizator Lex._.Lexi Guiman Lex._. Data 3 mai 2025 22:20:49
Problema Barbar Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.74 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]!='*') //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=-1; //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[poz.first][poz.second]+1<distanta[nou.first][nou.second]) //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
    cout << cautare_binara(); //afisam distanta maxima

    return 0;
}