Pagini recente » Cod sursa (job #1810171) | Cod sursa (job #214090) | Cod sursa (job #1844027) | Cod sursa (job #177404) | Cod sursa (job #2819870)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
//constanta ce ajuta la memorarea a celor doua coordonate intregi ca un singur numar in coada de parcurgere
#define D 1024
ifstream fin("barbar.in");
ofstream fout("barbar.out");
int R, C;
//coordonatele sursei si destinatiei
int Ii, Ji, If, Jf;
vector<vector<char>> m;
//matricea de lucru, cea pe care o putem modifica
vector<vector<char>> a;
//matricea in care se va marca ce celule au fost vizitate(folosita la parcurgerea in latime)
vector<vector<bool>> vizitat;
//functie care testeaza daca ne aflam in interiorul matricei
bool inside(int i, int j)
{
if(i >= 0 && i < R && j >=0 && j < C)
return true;
return false;
}
//subpogram care determina distanta maxima posibila care este data de distanta minima dintre un dragon si I
//sau dintre un dragon si O
int dmax()
{
//matrice care retine distanta de la fiecare dragon pana la fiecare celula din traseul parcurs
vector<vector<int>> d(R, vector<int>(C));
//vectori de deplasare pentru cele 4 direrctii
int di[4] = {-1, 1, 0, 0};
int dj[4] = {0, 0, -1, 1};
//pregatim matricea de vizitat pentru urmatoarea parcurgere
vizitat.clear();
vizitat.resize(R, vector<bool>(C));
//coada folosita la parcurgerea in latime
queue<int> q;
q.push(Ii*D+Ji);
q.push(If*D+Jf);
vizitat[Ii][Ji] = true;
vizitat[If][Jf] = true;
while(!q.empty())
{
//extragem urmatoarea celula din coada
int x = q.front();
q.pop();
//aflam coordonatele celulei extrase din coada
int i = x/D;
int j = x%D;
//incercam deplasare in fiecare din cele 4 directii posibile
for(int k=0; k<4; ++k)
{
int ni = i + di[k]; //noul i
int nj = j + dj[k]; //noul j
//verificam daca deplasandu-ne astfel ramanem in continuare in matrice,
//celula este libera, celula nu a mai fost vizitata si distanta este mai mica decat dist
if(inside(ni,nj) && !vizitat[ni][nj] && ( a[ni][nj] == 'D' || a[ni][nj] == '.') )
{
vizitat[ni][nj] = true;
q.push(ni*D+nj);
d[ni][nj] = d[i][j] + 1;
if(a[ni][nj] == 'D')
return d[ni][nj];
}
}
}
return 0;
}
//subprogram ce pune in matricea de lucru a pereti in jurul fiecarui dragon pe o raza egala cu distanta propusa
//data subprogramului "parcurgere"
void umplere(int dist)
{
//matrice care retine distanta de la fiecare dragon pana la fiecare celula din traseul parcurs
vector<vector<int>> d(R, vector<int>(C));
//vectori de deplasare pentru cele 4 direrctii
int di[4] = {-1, 1, 0, 0};
int dj[4] = {0, 0, -1, 1};
//pregatim matricea de vizitat pentru urmatoarea parcurgere
vizitat.clear();
vizitat.resize(R, vector<bool>(C));
//coada folosita la parcurgerea in latime
queue<int> q;
//parcurgem matricea pentru a gasi dragonii;
//odata gasit un dragon, acesta este pus in coada
for(int i = 0; i < R; ++i)
for(int j = 0; j < C; ++j)
if(a[i][j] == 'D')
{
q.push(i*D+j);
vizitat[i][j] = true;
}
while(!q.empty())
{
//extragem urmatoarea celula din coada
int x = q.front();
q.pop();
//aflam coordonatele celulei extrase din coada
int i = x/D;
int j = x%D;
//incercam deplasare in fiecare din cele 4 directii posibile
for(int k=0; k<4; ++k)
{
int ni = i + di[k]; //noul i
int nj = j + dj[k]; //noul j
//verificam daca deplasandu-ne astfel ramanem in continuare in matrice,
//celula este libera, celula nu a mai fost vizitata si distanta este mai mica decat dist
if(inside(ni,nj) && !vizitat[ni][nj] && a[ni][nj] == '.' && d[i][j] + 1 <= dist)
{
vizitat[ni][nj] = true;
q.push(ni*D+nj);
a[ni][nj] = '*';
d[ni][nj] = d[i][j] + 1;
}
}
}
}
//functia de parcurgere innlatime, care primeste o distanta minima fata de dragoni propusa
//si returneaza distanta primita daca parcurgerea este posibila sau -1 in caz contrar
int parcurgere(int dist)
{
//copiem matricea m in matricea de lucru a
a.resize(R, vector<char>(C));
for(int i = 0; i < R; ++i)
for(int j = 0; j < C; ++j)
a[i][j] = m[i][j];
if(dist > 1)
umplere(dist-1);
//vectori de deplasare pentru cele 4 direrctii
int di[4] = {-1, 1, 0, 0};
int dj[4] = {0, 0, -1, 1};
//pregatim matricea de vizitat pentru urmatoarea parcurgere
vizitat.clear();
vizitat.resize(R, vector<bool>(C));
//coada folosita la parcurgerea in latime
queue<int> q;
//vizitam celula sursa
q.push(Ii*D+Ji);
vizitat[Ii][Ji] = true;
while(!q.empty())
{
//extragem urmatoarea celula din coada
int x = q.front();
q.pop();
//aflam coordonatele celulei extrase din coada
int i = x/D;
int j = x%D;
//incercam deplasare in fiecare din cele 4 directii posibile
for(int k=0; k<4; ++k)
{
int ni = i + di[k]; //noul i
int nj = j + dj[k]; //noul j
//verificam daca deplasandu-ne astfel ramanem in continuare in matrice,
//celula este libera si celula nu a mai fost vizitata
if(inside(ni,nj) && !vizitat[ni][nj] && (a[ni][nj] == '.' || a[ni][nj] =='O' || a[ni][nj] =='D'))
{
//daca s-a ajuns in destinatie
if(ni == If && nj == Jf)
return dist;
vizitat[ni][nj] = true;
q.push(ni*D+nj);
}
}
}
//nu s-a putut ajunge in destinatie
return -1;
}
//functia care cauta binar distanta optima ce poate fi propusa functiei parcurgere,
//astfel incat sa se poata ajunge in destinatie
int solve()
{
//testam daca este posibil sa ajungem din sursa in destinatie
int rez = parcurgere(0);
if(rez == -1)
return rez;
//valorile intre care cautam binar
int st = 0;
int dr = dmax();
while(st <= dr)
{
int mij = (st + dr) / 2;
int r = parcurgere(mij);
//daca parcurgerea nu este posibila, inseamna ca distanta propusa este prea mare
//si trebuie micsorata
if(r == -1)
dr = mij - 1;
else //in caz contrat inseamna ca parcurgerea este posibila si incrcam sa marim distanta propusa
{
st = mij + 1;
//daca am gasit o distanta mai buna decat pana in acest punct
if(rez < r)
rez = r;
}
}
return rez;
}
int main()
{
fin >> R >> C;
//dimensionam matricea
m.resize(R, vector<char>(C));
//citim datel din matrice
for(int i=0; i<R; ++i)
for(int j=0; j<C; ++j)
{
fin >> m[i][j];
//determinam coordonatele sursei si ale destinatiei
if(m[i][j] == 'I')
{
Ii = i;
Ji = j;
}
if(m[i][j] == 'O')
{
If = i;
Jf = j;
}
}
fout << solve();
}