Cod sursa(job #2828130)

Utilizator icnsrNicula Ionut icnsr Data 6 ianuarie 2022 21:47:53
Problema Barbar Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.41 kb
#include <iostream>
#include <cstdint>
#include <iterator>
#include <algorithm>
#include <array>
#include <queue>
#include <numeric>

template<typename T>
class NumIter
{
public:
        using iterator_category = std::random_access_iterator_tag;
        using value_type = T;
        using difference_type = std::int64_t;
        using pointer = T;
        using reference = T;

        NumIter(const T x)
            : value(x)
        {
        }

        T operator*() const
        {
                return value;
        }

        NumIter& operator++()
        {
                ++value;
                return *this;
        }

        NumIter operator++(int)
        {
                const NumIter old{value};
                ++value;
                return old;
        }

        NumIter& operator--()
        {
                --value;
                return *this;
        }

        NumIter operator--(int)
        {
                const NumIter old{value};
                --value;
                return old;
        }

        NumIter& operator+=(const std::int64_t n)
        {
                value += n;
                return *this;
        }

        auto operator-(const NumIter& other) const
        {
                return static_cast<difference_type>(value) -
                       static_cast<difference_type>(other.value);
        }

        bool operator==(const NumIter& other) const
        {
                return value == other.value;
        }

private:
        T value = {};
};

static int R;
static int C;

struct Room
{
        bool operator==(const Room& other) const
        {
                return x == other.x && y == other.y;
        }

        bool valid() const
        {
                return 0 <= x && x < R && 0 <= y && y < C;
        }

        std::array<Room, 4> neighbours() const
        {
                const std::array<Room, 4> res = {
                    {{x, y - 1}, {x, y + 1}, {x - 1, y}, {x + 1, y}}};

                return res;
        }

        int x, y;
};

bool DFS(const Room src, const Room dest, const int K, std::vector<std::vector<char>>& visited,
         const std::vector<std::string>& mat, const std::vector<std::vector<int>>& dist)
{
        visited[src.x][src.y] = true;

        if(src == dest)
        {
                return true;
        }

        for(const Room& neigh : src.neighbours())
        {
                if(!neigh.valid() || visited[neigh.x][neigh.y] ||
                   mat[neigh.x][neigh.y] == '*' || mat[neigh.x][neigh.y] == 'D' ||
                   dist[neigh.x][neigh.y] < K)
                {
                        continue;
                }

                if(DFS(neigh, dest, K, visited, mat, dist) == true)
                {
                        return true;
                }
        }

        return false;
}

bool check_for_k(const Room& src, const Room& dest, const int K,
                 const std::vector<std::vector<int>>& dist,
                 const std::vector<std::string>& mat)
{
        auto visited = std::vector<std::vector<char>>(R, std::vector<char>(C, false));
        const bool res = dist[src.x][src.y] >= K && dist[dest.x][dest.y] >= K &&
                         DFS(src, dest, K, visited, mat, dist);
        return !res;
}

int main()
{

        std::freopen("barbar.in", "r", stdin);
        std::freopen("barbar.out", "w", stdout);

        std::ios_base::sync_with_stdio(false);
        std::cin.tie(nullptr);

        std::cin >> R >> C;
        std::cin.ignore();

        std::vector<std::string> mat(R);
        std::queue<Room> drag_q;
        Room src;
        Room dest;

        std::vector<std::vector<int>> dist(R, std::vector<int>(C));
        std::vector<std::vector<char>> visited(R, std::vector<char>(C, false));
        for(int i = 0; i < R; ++i)
        {
                std::getline(std::cin, mat[i]);
                for(int j = 0; j < C; ++j)
                {
                        if(mat[i][j] == 'I')
                        {
                                src = {i, j};
                        }

                        if(mat[i][j] == 'O')
                        {
                                dest = {i, j};
                        }

                        if(mat[i][j] == 'D')
                        {
                                drag_q.push(Room{i, j});
                                dist[i][j] = 0;
                                visited[i][j] = true;
                        }
                }
        }

        while(!drag_q.empty())
        {
                const auto c_room = drag_q.front();
                drag_q.pop();

                for(const Room& r : c_room.neighbours())
                {
                        if(!r.valid() || visited[r.x][r.y] || mat[r.x][r.y] == '*')
                        {
                                continue;
                        }

                        drag_q.push(r);
                        dist[r.x][r.y] = 1 + dist[c_room.x][c_room.y];
                        visited[r.x][r.y] = true;
                }
        }

        int res = *std::lower_bound(NumIter<int>{1}, NumIter<int>{R * C}, true,
                                    [&](const int i1, const int i2)
                                    {
                                            return check_for_k(src, dest, i1, dist, mat) < i2;
                                    });

        if(res == 1)
        {
                puts("-1");
                return 0;
        }

        --res;
        std::cout << res << '\n';
}