백준 3055_탈출 문제풀이 in C++

  1. 문제 URL
  2. 문제 요구사항
  3. 접근 방법
  4. 풀이 순서
  5. 소스코드
  6. 문제 풀이 결과

문제 URL


https://www.acmicpc.net/problem/3055

문제 요구사항


  • 사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다.
  • 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제일 친한 친구인 비버의 굴로 가능한 빨리 도망가 홍수를 피하려고 한다.
  • 티떱숲의 지도는 R행 C열로 이루어져 있다. 비어있는 곳은 ‘.’로 표시되어 있고, 물이 차있는 지역은 ‘*’, 돌은 ‘X’로 표시되어 있다. 비버의 굴은 ‘D’로, 고슴도치의 위치는 ‘S’로 나타내어져 있다.
  • 매 분마다 고슴도치는 현재 있는 칸과 인접한 네 칸 중 하나로 이동할 수 있다.
  • (위, 아래, 오른쪽, 왼쪽) 물도 매 분마다 비어있는 칸으로 확장한다.
  • 물이 있는 칸과 인접해있는 비어있는 칸(적어도 한 변을 공유)은 물이 차게 된다.
  • 물과 고슴도치는 돌을 통과할 수 없다. 또, 고슴도치는 물로 차있는 구역으로 이동할 수 없고, 물도 비버의 소굴로 이동할 수 없다.
  • 티떱숲의 지도가 주어졌을 때, 고슴도치가 안전하게 비버의 굴로 이동하기 위해 필요한 최소 시간을 구하는 프로그램을 작성하시오.
  • 고슴도치는 물이 찰 예정인 칸으로 이동할 수 없다.
  • 즉, 다음 시간에 물이 찰 예정인 칸으로 고슴도치는 이동할 수 없다. 이동할 수 있으면 고슴도치가 물에 빠지기 때문이다.
  • 첫째 줄에 50보다 작거나 같은 자연수 R과 C가 주어진다.
  • 다음 R개 줄에는 티떱숲의 지도가 주어지며, 문제에서 설명한 문자만 주어진다. ‘D’와 ‘S’는 하나씩만 주어진다.
  • 첫째 줄에 고슴도치가 비버의 굴로 이동할 수 있는 가장 빠른 시간을 출력한다.
  • 만약, 안전하게 비버의 굴로 이동할 수 없다면, “KAKTUS”를 출력한다.

접근 방법


  • 고슴도치와 물에 대해서 BFS를 수행하도록 하고, 고슴도치의 경우 탐색 시간을 구해야 하므로, checked ( int형 배열)을 이용해서 비용을 계산한다.

풀이 순서


  1. R과 C를 입력 받고 해당 크기만큼의 map 정보를 입력 받는다.
    • 이때, 맵의 정보가 ‘D’일때, ‘S’일때, ‘*’ 일때 각각의 정보를 변수에 저장한다.
  2. BFS 수행
    • hadge_q에 startX, startY를 넣고, visited의 startX, startY = true를 넣는다.
    • hadge_q가 empty일 때까지 반복
    • water_q의 사이즈만큼 for문을 반복하여 water에 대해서 먼저 bfs 전이 를 한다.
    • 이후, hadge_q의 사이즈만큼 for문을 반복하여 1차 고슴도치 이동 bfs 탐색을 한다.
    • 이때, 다음 방문 정점이 ‘D’라면 flag 변수에 true를 준다.
    • 이와 같은 작업 반복
  3. flag가 true라면 checked의 endX, endY 좌표의 값을 출력, false라면 “KAKTUS” 출력

소스코드


#include <iostream>
#include <vector>
#include <queue>

using namespace std;

int R, C;
char map[50][50];
bool visited[50][50] = { false, };
int checked[50][50] = { 0, };
int startX, startY;
queue<pair<int, int>> water_q;
int endX, endY;

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

bool flag = false;

void input() {
	cin >> R >> C;

	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			cin >> map[i][j];

			if (map[i][j] == 'S') {
				startX = i;
				startY = j;
			}
			else if (map[i][j] == '*') {
				water_q.push({ i, j });
			}
			else if (map[i][j] == 'D') {
				endX = i;
				endY = j;
			}
		}
	}
}


void bfs() {
	visited[startX][startY] = true;

	queue<pair<int, int>> hadge_q;

	hadge_q.push({ startX, startY });
	int date_time = -1;
	while (!hadge_q.empty()) {
		if (flag)
			return;

		// 물 전이 시키고 시작함
		int water_size = water_q.size();

		for (int i = 0; i < water_size; i++) {
			int w_x = water_q.front().first;
			int w_y = water_q.front().second;

			water_q.pop();

			for (int j = 0; j < 4; j++) {
				int next_w_x = w_x + dx[j];
				int next_w_y = w_y + dy[j];

				if (next_w_x >= 0 && next_w_y >= 0 && next_w_x < R && next_w_y < C) {
					if (map[next_w_x][next_w_y] == '.') {
						water_q.push({ next_w_x , next_w_y });
						map[next_w_x][next_w_y] = '*';
					}
				}
			}
		}

		int hadge_size = hadge_q.size();
		for (int i = 0; i < hadge_size; i++) {
			int h_x = hadge_q.front().first;
			int h_y = hadge_q.front().second;

			int now_cost = checked[h_x][h_y];

			hadge_q.pop();

			for (int i = 0; i < 4; i++) {
				int next_h_x = h_x + dx[i];
				int next_h_y = h_y + dy[i];

				if (next_h_x >= 0 && next_h_y >= 0 && next_h_x < R && next_h_y < C) {
					if (!visited[next_h_x][next_h_y] || checked[next_h_x][next_h_y] > now_cost + 1) {
						if (map[next_h_x][next_h_y] == '.') {
							visited[next_h_x][next_h_y] = true;
							checked[next_h_x][next_h_y] = now_cost + 1;
							hadge_q.push({ next_h_x , next_h_y });
						}
						else if (map[next_h_x][next_h_y] == 'D') {
							checked[next_h_x][next_h_y] = now_cost + 1;
							flag = true;
						}
					}
				}
			}

		}
	}

}

void solution() {
	bfs();
}

void output() {
	if (flag)
		cout << checked[endX][endY];
	else
		cout << "KAKTUS";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	input();
	solution();
	output();

	return 0;
}

문제 풀이 결과