Cod sursa(job #2208462)

Utilizator danyvsDan Castan danyvs Data 29 mai 2018 21:18:07
Problema Barbar Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.89 kb
#include <fstream>

using namespace std;

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

const int NMAX = 1005;

struct coord {
    int x, y;
};

// date de intrare
int A[NMAX][NMAX], n, m;
int xS, yS, xF, yF; // coordonate plecare si sosire
int ans; // rezultat

// dragoni
int D[NMAX][NMAX]; // matrice dragoni: D[i][j] = distanta pana la cel mai apropiat dragon
coord Qd[NMAX * NMAX]; // coada dragoni
int headQd, dimQd;

// vectori de deplasare
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};

void citire() {
    fin >> n >> m;
    for (int i = 1; i <= n; ++ i) {
        char str[NMAX];
        fin >> str;
        for (int j = 1; j <= m; ++ j)
            switch (str[j - 1]) {
                case '.':
                    // camera libera => se poate intra
                    A[i][j] = 0;
                    D[i][j] = 0;
                    break;
                case '*':
                    // perete => nu se poate intra
                    A[i][j] = -1;
                    D[i][j] = -1;
                    break;
                case 'D':
                    // dragon
                    A[i][j] = 0;
                    D[i][j] = 1;
                    ++ dimQd;
                    Qd[dimQd].x = i;
                    Qd[dimQd].y = j;
                    break;
                case 'I':
                    // loc de plecare
                    A[i][j] = 1;
                    D[i][j] = 0;
                    xS = i;
                    yS = j;
                    break;
                case 'O':
                    // loc de sosire
                    A[i][j] = 0;
                    D[i][j] = 0;
                    xF = i;
                    yF = j;
                    break;
            }
    }
}

void bordare(int A[NMAX][NMAX], int n, int m) {
    // bordare matrice
    for (int i = 0; i <= n + 1; ++ i)
        A[i][0] = A[i][m + 1] = -1;
    for (int j = 0; j <= m + 1; ++ j)
        A[0][j] = A[n + 1][j] = -1;
}

void detDistDragoni() {
    // determinare distanta pana la cel mai apropiat dragon (pentru fiecare camera libera)

    // Lee pentru determinare distante
    headQd = 1; // se garanteaza ca exista cel putin un dragon
    while (headQd <= dimQd) {
        int l = Qd[headQd].x;
        int c = Qd[headQd].y;
        ++ headQd;
        for (int i = 0; i < 4; ++ i) {
            // determinare vecini
            int ln = l + dx[i];
            int cn = c + dy[i];
            if (!D[ln][cn] || D[ln][cn] > D[l][c] + 1) {
                // s-a gasit cel mai apropiat dragon sau s-a gasit o distanta mai mica
                D[ln][cn] = D[l][c] + 1;
                ++ dimQd;
                Qd[dimQd].x = ln;
                Qd[dimQd].y = cn;
            }
        }
    }

    // actualizare distante
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= m; ++ j)
            if (D[i][j] > 0)
                -- D[i][j];
}

void copiereMatrici(int dest[NMAX][NMAX], int src[NMAX][NMAX]) {
    // dest = src
    for (int i = 0; i <= n + 1; ++ i)
        for (int j = 0; j <= m + 1; ++ j)
            dest[i][j] = src[i][j];
}

int B[NMAX][NMAX]; // matrice auxiliara pentru a nu pierde datele din A
coord Q[NMAX * NMAX]; // coada pentru Lee

bool Lee(int dist) {

    int head = 1, dim = 0;

    if (D[xS][yS] < dist) {
        // camera de plecare este prea aproape de un dragon
        return 0;
    }

    copiereMatrici(B, A);
    ++ dim;
    Q[dim].x = xS;
    Q[dim].y = yS;
    while (head <= dim) {
        int l = Q[head].x;
        int c = Q[head].y;
        ++ head;
        for (int i = 0; i < 4; ++ i) {
            // determinare vecini
            int ln = l + dx[i];
            int cn = c + dy[i];
            if (!B[ln][cn] && D[ln][cn] >= dist) {
                // se poate accesa camera curenta
                // nu ne intereseaza cea mai mica distanta, ci doar sa ajugem la destinatie
                // din aceasta cauza, nu actualizam cand gasim o distanta mai buna
                B[ln][cn] = B[l][c] + 1;
                ++ dim;
                Q[dim].x = ln;
                Q[dim].y = cn;
            }
        }
    }

    return B[xF][yF];
}

inline int max(const int& a, const int& b) {
    return a > b ? a : b;
}

void cautareBinara() {
    // cautare binara
    ans = -1;
    int lo = 0, hi = max(n, m);
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        int res = Lee(mid);
        if (res) {
            // s-a putut ajunge cu distanta dist
            // incercam sa imbunatatim
            lo = mid + 1;
            ans = max(ans, mid);
        }
        else
            hi = mid - 1;
    }
}

int main() {
    citire();
    fin.close();
    bordare(A, n, m);
    bordare(D, n, m);
    detDistDragoni();
    cautareBinara();
    fout << ans << "\n";
    fout.close();
    return 0;
}