백조의 호수

Wonseok Lee·2021년 11월 13일
0

Beakjoon Online Judge

목록 보기
60/117
post-thumbnail

Problem link: https://www.acmicpc.net/problem/3197

하루가 지날 때마다 빙판을 녹여주고, 한 백조에서 BFS를 수행해서 다른 백조로 가는 경로가 있는가를 살펴주면 된다.

단, 매번 빙판을 녹일 때마다 BFS를 새로 수행한다면 비효율적이므로 BFS 수행 시 빙판이라서 진행하지 못했던 정점들을 별도로 저장해두고, 다음 BFS에서는 이들부터 BFS를 시작한다.

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <set>

using namespace std;

const int kMaxR = 1500;
const int kMaxC = 1500;

int R, C;
string MAP[kMaxR];

int SWAN;
int VISIT[kMaxR][kMaxC];
vector<int> ICEBURGS;

const int dr[4] = { -1, 0, 1, 0 };
const int dc[4] = { 0, 1, 0, -1 };

set<int> next_iceburgs;
queue<int> q;
queue<int> boundary;

void FindSwan(void)
{
  for (int r = 0; r < R; ++r)
  {
    for (int c = 0; c < C; ++c)
    {
      if (MAP[r][c] == 'L')
      {
        SWAN = r * C + c;
        MAP[r][c] = '.';
        return;
      }
    }
  }
}

void FindIceburgs(void)
{
  for (int r = 0; r < R; ++r)
  {
    for (int c = 0; c < C; ++c)
    {
      if (MAP[r][c] == 'X')
      {
        bool will_be_melted = false;
        for (int d = 0; d < 4; ++d)
        {
          int nr = r + dr[d];
          int nc = c + dc[d];
          if (0 > nr || nr >= R || 0 > nc || nc >= C)
          {
            continue;
          }

          if (MAP[nr][nc] == 'L' || MAP[nr][nc] == '.')
          {
            will_be_melted = true;
            break;
          }
        }

        if (will_be_melted)
        {
          ICEBURGS.emplace_back(r * C + c);
        }
      }
    }
  }
}

void Melt(void)
{
  next_iceburgs.clear();

  for (const auto& iceburg : ICEBURGS)
  {
    int r = iceburg / C;
    int c = iceburg % C;

    MAP[r][c] = '.';
  }

  for (const auto& iceburg : ICEBURGS)
  {
    int r = iceburg / C;
    int c = iceburg % C;

    for (int d = 0; d < 4; ++d)
    {
      int nr = r + dr[d];
      int nc = c + dc[d];

      if (0 > nr || nr >= R || 0 > nc || nc >= C || MAP[nr][nc] != 'X')
      {
        continue;
      }

      next_iceburgs.insert(nr * C + nc);
    }
  }

  ICEBURGS.clear();

  for (const auto& iceburg : next_iceburgs)
  {
    ICEBURGS.emplace_back(iceburg);
  }
}

bool Bfs(queue<int>& boundary)
{
  while (!boundary.empty())
  {
    int r = boundary.front() / C;
    int c = boundary.front() % C;
    boundary.pop();

    VISIT[r][c] = 1;
    q.emplace(r * C + c);
  }

  while (!q.empty())
  {
    int here = q.front();
    q.pop();

    int r = here / C;
    int c = here % C;

    for (int d = 0; d < 4; ++d)
    {
      int nr = r + dr[d];
      int nc = c + dc[d];

      if (0 > nr || nr >= R || 0 > nc || nc >= C || VISIT[nr][nc] == 1)
      {
        continue;
      }

      if (VISIT[nr][nc] == 0 && MAP[nr][nc] == 'L')
      {
        return true;
      }
      else if (VISIT[nr][nc] == 0 && MAP[nr][nc] == '.')
      {
        VISIT[nr][nc] = 1;
        q.emplace(nr * C + nc);
      }
      else if (VISIT[nr][nc] == 0 && MAP[nr][nc] == 'X')
      {
        VISIT[nr][nc] = 2;
        boundary.emplace(nr * C + nc);
      }
    }
  }

  return false;
}

int Solve(void)
{
  FindSwan();
  FindIceburgs();

  boundary.emplace(SWAN);

  int day = 0;
  while (true)
  {
    if (Bfs(boundary))
    {
      break;
    }

    Melt();

    ++day;
  }

  return day;
}

int main(void)
{
  // For Faster IO
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read Inputs
  cin >> R >> C;
  for (int r = 0; r < R; ++r)
  {
    cin >> MAP[r];
  }

  // Solve
  cout << Solve() << '\n';

  return 0;
}
profile
Pseudo-worker

0개의 댓글