백준 14503_로봇 청소기 문제풀이 in C++

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

문제 URL


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

문제 요구사항


  • 로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1 크기의 정사각형 칸으로 나누어져 있다.
  • 각각의 칸은 벽( 1 ) 또는 빈 칸 ( 0 )이다.
  • 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북 중 하나다.
  • 지도의 북쪽에서부터 r번째, 서쪽에서부터 c번째로 위치한 칸은 (r, c)로 나타낼 수 있다.
  • 로봇 청소기는 다음과 같이 작동한다.
    • 1 현재 위치를 청소한다.
    • 2 현재 위치에서 다음을 반복하면서 인접한 칸을 탐색한다.
      • a. 현재 위치의 바로 왼쪽에 아직 청소하지 않은 빈 공간이 존재한다면, 왼쪽 방향으로 회전한 다음 한 칸을 전진하고 1번으로 돌아간다. 그렇지 않을 경우, 왼쪽 방향으로 회전한다. 이때, 왼쪽은 현재 바라보는 방향을 기준으로 한다.
      • b. 1번으로 돌아가거나 후진하지 않고 2a번 단계가 연속으로 네 번 실행되었을 경우, 바로 뒤쪽이 벽이라면 작동을 멈춘다. 그렇지 않다면 한 칸 후진한다.
  • 첫째 줄에 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 50)
  • 둘째 줄에 로봇 청소기가 있는 칸의 좌표 (r, c)와 바라보는 방향 d가 주어진다. 청소기가 있는 위치는 무조건 0이다.
    • d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우에는 서쪽을 바라보고 있는 것이다.
  • 셋째 줄부터 N개의 줄에 장소의 상태가 북쪽부터 남쪽 순서대로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 빈 칸은 0, 벽은 1로 주어진다. 지도의 첫 행, 마지막 행, 첫 열, 마지막 열에 있는 모든 칸은 벽이다.

접근 방법


  • 문제에서 주어진 로직대로 구현을 한다면 충분히 풀 수 있는 문제이다. 다만, 청소 조건 중 하나인 2 - b 조건에서 iterateCase(2a번 단계가 연속으로 네 번 실행 됐는지 check하는 변수)를 초기화를 제대로 해주지 않아 맵을 그리고, 디버깅 해야하는 문제가 생겼었다…

풀이 순서


  • 맵의 크기 N과 M을 입력 받는다.
  • 로봇의 시작 점 x, y를 입력 받고, 초기 로봇이 바라보는 방향 direction을 입력 받는다.
  • 맵의 크기만큼 맵의 정보를 입력 받는다.
  • BFS 수행
    • queue에 시작점 x, y를 넣는다.
    • queue가 빌 때까지 while문 반복 수행
      • queue의 첫 번쨰 원소 중 first 값을 xx에 넣는다.
      • queue의 첫 번째 원소 중 second 값을 yy에 넣는다.
      • queue의 첫 번쨰 원소 pop( )
      • for문 수행 ( 동 서 남 북 회전하며 탐색) –> 2-a 청소 조건 수행
      • direction 값에 현재 direction + 3 % 4를 하게 되면 로봇이 현재 바라보고 있는 방향의 왼쪽이 되게 된다.
      • next_x의 값에 xx + dx[direction] 값을 넣는다.
      • next_y의 값에 yy + dy[direction] 값을 넣는다.
      • next_x, next_y가 0 이상이고, 각각 N과 M보다 작고, checkMap[next_x][next_y]의 값이 false( 방문 하지 않음) 이고, map의 [next_x][next_y] 값이 0일 때, iterateCase = 0으로 초기화 해주고, queue에 next_x, next_y를 넣어주고, 해당 for문을 종료한다.
      • 만약, 위 조건을 충족하지 못한다면, iterateCase +=1을 해주고, for문을 계속 수행한다.
      • for문 종료 후, 다음 조건문을 수행한다. –> 2-b 청소 조건 수행
      • 만약, iterateCase 값이 4라면, next_x에 xx + dx[(direction + 2) % 4], next_y에 yy + dy[(direction + 2) % 4]를 한다.
      • map[ next_x ] [ next_y ] 값이 1이라면, 모든 탐색을 종료한다.
      • 아니라면, iterateCase = 0으로 초기화하고, queue에 next_x, next_y 값을 넣는다.
    • 이와 같은 작업 반복
  • BFS가 종료 된 후, checkMap을 2중 for문으로 탐색하여, true인 값을 모두 더해 그 더한 값을 출력한다.

소스코드


#include <iostream>
#include <queue>

using namespace std;

int N, M;
int startX, startY, now_direction;
int map[50][50];
bool checkMap[50][50];
int dx[] = { -1, 0, 1, 0 };
int dy[] = { 0, 1, 0, -1 };
int iterateCase = 0;
/*
* 청소 룰
* 1. 현재 위치 청소
* 2. a. 현재 위치의 바로 왼쪽에 아직 청소하지 않은 빈 공간이 존재한다면, 왼쪽 방향 한 칸을 전진하고 1번으로 돌아간다.
        그렇지 않을 경우, 왼쪽 방향으로 회전한다. 이때, 왼쪽은 현재 바라보는 방향을 기준으로 한다.
	 b. 1번으로 돌아가거나 후진하지 않고 2-a번 단계가 연속으로 네 번 실행되었을 경우, 바로 뒤쪽이 벽이라면 작동을 멈추고 벽이 아니라면 한 칸 후진한다.
*/

void input() {
	cin >> N >> M;

	// row, col, direction
	// now_direction : 0 (북), 1(동), 2(남), 3(서)
	cin >> startX >> startY >> now_direction;

	// 장소 상태 : 0은 빈칸, 1은 벽
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> map[i][j];
		}
	}
}

void BFS() {
	queue<pair<int, int>> q;

	q.push({ startX, startY });

	while (!q.empty()) {
		int xx = q.front().first;
		int yy = q.front().second;

		checkMap[xx][yy] = true;

		q.pop();
		cout << "now dir :" << now_direction << "\n";

		// 청소 조건 2-a 수행
		for (int i = 0; i < 4; i++) {
			now_direction = (now_direction + 3) % 4;

			int nx = xx + dx[now_direction];
			int ny = yy + dy[now_direction];

			if (nx >= 0 && ny >= 0 && nx < N && ny < M) {
				if (checkMap[nx][ny] == false && map[nx][ny] == 0) {
					iterateCase = 0;
					q.push({ nx, ny });
					break;
				}
				iterateCase++;
			}
		}

		// 청소 조건 2-b 수행
		if (iterateCase == 4) {
			int nx = xx + dx[(now_direction + 2) % 4];
			int ny = yy + dy[(now_direction + 2) % 4];

			if (map[nx][ny] == 1)
				break;
			else {
				iterateCase = 0;
				q.push({ nx, ny });
			}
			continue;
		}
	}
}

void solution() {
	memset(checkMap, false, sizeof(checkMap));
	BFS();
}

void output() {
	int sum = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (checkMap[i][j])
				sum += 1;
		}
	}

	cout << sum;
}

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

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

	return 0;
}

문제 풀이 결과