Cod sursa(job #2812331)

Utilizator icnsrNicula Ionut icnsr Data 4 decembrie 2021 13:29:20
Problema Barbar Scor 50
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.18 kb
#include <iostream>
#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, std::vector<std::vector<char>>& visited,
         const std::vector<std::vector<char>>& mat)
{
        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')
                {
                        continue;
                }

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

        return false;
}

void DFS_fill(const Room src, int current_depth, const int g_max_depth,
              std::vector<std::vector<char>>& visited, std::vector<std::vector<char>>& mat)
{
        if(mat[src.x][src.y] == 'D')
        {
                current_depth = g_max_depth;
        }

        if(current_depth < 0)
        {
                return;
        }

        visited[src.x][src.y] = true;
        mat[src.x][src.y] = 'D';

        for(const Room& neigh : src.neighbours())
        {
                if(!neigh.valid() || visited[neigh.x][neigh.y])
                {
                        continue;
                }

                DFS_fill(neigh, current_depth - 1, g_max_depth, visited, mat);
        }
}

bool check_for_k(const Room src, const Room dest, const int K,
                 const std::vector<Room>& dragons_pos, std::vector<std::vector<char>> mat)
{
        std::vector<std::vector<char>> visited(R, std::vector<char>(C, false));

        for(const Room& r : dragons_pos)
        {
                DFS_fill(r, K - 1, K - 1, visited, mat);
        }

        visited = std::vector<std::vector<char>>(R, std::vector<char>(C, false));

        bool res = DFS(src, dest, visited, mat);
        return !res;
}

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

        std::cin >> R >> C;

        std::vector<std::vector<char>> mat(R, std::vector<char>(C));
        std::vector<Room> dragons_pos;
        Room src;
        Room dest;
        for(int i = 0; i < R; ++i)
        {
                for(int j = 0; j < C; ++j)
                {
                        std::cin >> mat[i][j];

                        if(mat[i][j] == 'I')
                        {
                                src = {i, j};
                        }

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

                        if(mat[i][j] == 'D')
                        {
                                dragons_pos.push_back(Room{i, j});
                        }
                }
        }

        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, dragons_pos, mat) < i2;
                              });

        if(res == 1)
        {
                std::cout << -1 << '\n';
                return 0;
        }

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