Cod sursa(job #2075958)

Utilizator dariusdariusMarian Darius dariusdarius Data 25 noiembrie 2017 21:28:43
Problema Barbar Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.34 kb
#include <fstream>
#include <iostream>
#include <queue>
#include <vector>

#include <cstring>

const int MAX_N = 1005;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {-1, 0, 1, 0};

class Matrix {
private:
    std::vector< std::vector<int> > data;
public:
    Matrix() {}
    Matrix(int n, int m, int val=0) {
        data.assign(n, std::vector<int>(m, val));
    }

    int n() const {
        return data.size();
    }

    int m() const {
        return data[0].size();
    }

    bool in(int x, int y) const {
        return 0 <= x && x < n() && 0 <= y && y < m();
    }

    int get(int x, int y) const {
        return data[x][y];
    }

    void set(int x, int y, int val) {
        data[x][y] = val;
    }

    std::vector< std::pair<int, int> > Neighbours(int x, int y) const {
        std::vector< std::pair<int, int> > ret;
        for (int d = 0; d < 4; ++ d) {
            std::pair<int, int> neighbour = {x + dx[d], y + dy[d]};
            if (in(neighbour.first, neighbour.second)) {
                ret.push_back(neighbour);
            }
        }
        return ret;
    }
};

bool visited[1005][1005];

bool CanTravel(int dist, std::pair<int, int> start, std::pair<int, int> stop, const Matrix &dragon_dists, const std::vector< std::vector<bool> > &walls) {
    if (dragon_dists.get(start.first, start.second) < dist) {
        return false;
    }
    std::queue< std::pair<int, int> > q;
    memset(visited, 0, sizeof visited);
    q.push(start);
    visited[start.first][start.second] = true;
    int n = dragon_dists.n(), m = dragon_dists.m();
    while (!q.empty()) {
        auto pos = q.front();
        q.pop();
        for (int d = 0; d < 4; ++ d) {
            std::pair<int, int> new_pos = {pos.first + dx[d], pos.second + dy[d]};
            if (0 > new_pos.first || n <= new_pos.first || 0 > new_pos.second || m <= new_pos.second) {
                continue;
            }
            if (!visited[new_pos.first][new_pos.second] && !walls[new_pos.first][new_pos.second] && dragon_dists.get(new_pos.first, new_pos.second) >= dist) {
                if (new_pos == stop) {
                    return true;
                }
                visited[new_pos.first][new_pos.second] = true;
                q.push(new_pos);
            }
        }
    }
    return false;
}

Matrix bfs(const std::vector< std::pair<int, int> > &dragons, const std::vector< std::vector<bool> > &walls) {
    std::queue< std::pair<int, int> > q;
    Matrix dist(walls.size(), walls[0].size(), 1000000000);
    for (auto dragon: dragons) {
        dist.set(dragon.first, dragon.second, 0);
        q.push(dragon);
    }
    while (!q.empty()) {
        auto pos = q.front();
        q.pop();
        for (auto new_pos : dist.Neighbours(pos.first, pos.second)) {
            if (dist.get(new_pos.first, new_pos.second) == 1000000000 && !walls[new_pos.first][new_pos.second]) {
                dist.set(new_pos.first, new_pos.second, dist.get(pos.first, pos.second) + 1);
                q.push(new_pos);
            }
        }
    }
    return dist;
}

int main()
{
    std::ifstream cin("barbar.in");
    std::ofstream cout("barbar.out");
    char line[1005];
    int n, m;
    cin >> n >> m;
    std::pair<int, int> start, stop;
    std::vector< std::pair<int, int> > dragons;
    std::vector< std::vector<bool> > walls(n, std::vector<bool>(m, false));
    for (int i = 0; i < n; ++ i) {
        cin >> line;
        for (int j = 0; j < m; ++ j) {
            if (line[j] == '.') {
                continue;
            }
            if (line[j] == 'D') {
                dragons.push_back({i, j});
                continue;
            }
            if (line[j] == '*') {
                walls[i][j] = true;
                continue;
            }
            if (line[j] == 'I') {
                start = {i, j};
            } else {
                stop = {i, j};
            }
        }
    }
    auto dragon_dists = bfs(dragons, walls);
    int left = 0, right = n * m, best = -1;
    while (left <= right) {
        int middle = (left + right) / 2;
        if (CanTravel(middle, start, stop, dragon_dists, walls)) {
            best = middle;
            left = middle + 1;
        } else {
            right = middle - 1;
        }
    }
    cout << best << "\n";
    return 0;
}