Cod sursa(job #1615164)

Utilizator BrandonChris Luntraru Brandon Data 26 februarie 2016 14:11:46
Problema Barbar Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.31 kb
#include <fstream>
#include <queue>
#include <cstring>

#define INF 0x3f3f3f3f

using namespace std;

ifstream cin("barbar.in");
ofstream cout("barbar.out");

class Coord {
public:
    int x, y;
    inline bool operator == (Coord other) {
        return x == other.x and y == other.y;
    }
};

queue <Coord> q;

Coord paft, drag[1000005], ext;
int n, m, cost[1005][1005], drag_nr = 1, min_cost = INF;
int dir[4][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
bool used[1005][1005];

void bord_matrix() {
    for(int i = 0; i <= n + 1; ++i) {
        cost[i][0] = -1;
        cost[i][m + 1] = -1;
    }

    for(int i = 0; i <= m + 1; ++i) {
        cost[0][i] = -1;
        cost[n + 1][i] = -1;
    }
}

void fill_dragon() {
    for(int i = 1; i < drag_nr; ++i) {
        cost[drag[i].x][drag[i].y] = 1;
        used[drag[i].x][drag[i].y] = true;
        q.push(drag[i]);
    }

    while(!q.empty()) {
        Coord frn = q.front();
        q.pop();

        for(int i = 0; i < 4; ++i) {
            int new_x = frn.x + dir[i][0];
            int new_y = frn.y + dir[i][1];

            if(cost[new_x][new_y] == -1 or used[new_x][new_y]) {
                continue;
            }

            used[new_x][new_y] = true;

            if(cost[frn.x][frn.y] + 1 < cost[new_x][new_y] or !cost[new_x][new_y]) {
                q.push({new_x, new_y});
                cost[new_x][new_y] = cost[frn.x][frn.y] + 1;
            }
        }
    }
}

inline bool bfs(int min_cost) {
    q.push(paft);
    used[paft.x][paft.y] = true;
    if(cost[paft.x][paft.y] < min_cost) {
        return false;
    }

    while(!q.empty()) {

        Coord frn = q.front();
        q.pop();

        for(int i = 0; i < 4; ++i) {
            Coord nxt;
            nxt.x = frn.x + dir[i][0];
            nxt.y = frn.y + dir[i][1];

            if(used[nxt.x][nxt.y] or cost[nxt.x][nxt.y] == -1) {
                continue;
            }

            used[nxt.x][nxt.y] = true;

            if(cost[nxt.x][nxt.y] >= min_cost) {
                q.push(nxt);

                if(ext == nxt) {
                    return true;
                }
            }
        }
    }

    return false;
}

inline void init_q() {
    while(!q.empty()) {
        q.pop();
    }
}

int bin_search(int l, int r) {
    int med, ans = -1;

    while(l <= r) {
        med = (l + r) / 2;
        memset(used, 0, sizeof used);
        init_q();

        if(bfs(med)) {
            l = med + 1;
            ans = med;
        }
        else {
            r = med - 1;
        }
    }

    return ans;
}

int main() {
    cin >> n >> m;

    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            char ch;
            cin >> ch;

            if(ch == 'I') {
                paft = {i, j};
            }
            else if(ch == 'D') {
                drag[drag_nr] = {i, j};
                ++drag_nr;
            }
            else if(ch == '*') {
                cost[i][j] = -1;
            }
            else if(ch == 'O') {
                ext = {i, j};
            }
        }
    }

    bord_matrix();
    fill_dragon();
    int ans = bin_search(0, n + m + 1);

    if(ans != -1) {
        --ans;
    }

    cout << ans << '\n';
    return 0;
}