[BOJ][백준 14503] 로봇 청소기 - C++

2023. 3. 24. 13:35IT이모) 알고리즘 문제풀이/백준 문제풀이

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

 

14503번: 로봇 청소기

첫째 줄에 방의 크기 $N$과 $M$이 입력된다. $(3 \le N, M \le 50)$  둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 $(r, c)$와 처음에 로봇 청소기가 바라보는 방향 $d$가 입력된다. $d$가 $0$인 경우 북쪽

www.acmicpc.net

백준 사이트의 14503번 문제, 로봇 청소기 문제다.

본인은 C++로 문제풀이를 진행하였다.


0. 문제 읽기

문제 입력과 출력

로봇 청소기 작동 방식은 다음과 같다.

  • 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
  • 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우,
    ->  바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
    ->  바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
  • 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우,
    ->  반시계 방향으로 90도 회전한다.
    ->  바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다.
       1번으로 돌아간다.

1. 문제풀이 아이디어

  • 규칙대로 갈 수 있는 최대까지 이동하게 하는 단순 구현.
  • 인자로 청소기의 방향을 가져가자.
  • 그냥 작동 규칙대로 쭉 구현하면 될듯.

2. 코드 핵심 부분

1) 문제 풀이의 전부인 solve함수,

   구현이 전부인 문제이고 특별한 알고리즘이 필요없어서 이 함수가 문제풀이의 전부다.

   주석을 보면 알 수 있듯이 작동 규칙을 그대로 가져와 이를 코드로 구현했다.

// 문제풀이 함수
int solve() {

	int Cnt = 0;

	while (1) {

		// 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
		if (Map[Sy][Sx] == 0) {
			Cnt++;
			Map[Sy][Sx] = 2;
			continue;
		}

		int temp = Dir;

		int flag = 0;

		// 주변 4칸 체크 (반시계 방향으로)
		for (int i = 0; i < 4; i++) {

			Dir = (Dir + 3) % 4;

			int ny = Sy + diry[Dir];
			int nx = Sx + dirx[Dir];

			if (Map[ny][nx] == 0) {
				flag = 1;
				Sy = ny, Sx = nx;
				break;
			}

		}

		// 청소되지 않은 빈 칸이 없는 경우
		if (flag == 0) {
			Dir = (Dir + 2) % 4;
			int ny = Sy + diry[Dir];
			int nx = Sx + dirx[Dir];
			// 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
			if (Map[ny][nx] != 1) {
				Sy = ny, Sx = nx;
				Dir = temp;
			}

			// 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
			else {
				break;
			}
		}
	}

	return Cnt;
}

3. 전체 코드

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

/*
1. 문제읽기 (로봇청소기 작동방식)
	현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
	현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우,
	  바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
	  바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
	현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우,
	  반시계 방향으로 90도 회전한다.
	  바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다.
	  1번으로 돌아간다.
*/

/*
2. 아이디어
	규칙대로 갈 수 있는 최대까지 이동하게 하는 단순 구현.
	인자로 청소기의 방향을 가져가자.
	그냥 규칙대로 쭉 구현하면 될듯.
*/

// 필요 인자들
int N, M; // 세로, 가로 (3 <= N, M <= 50)
int Sy, Sx, Dir; // 로봇위치, 방향
int Map[50][50];

// 방향배열 (북 동 남 서)
int diry[] = { -1, 0, 1, 0 };
int dirx[] = { 0, 1, 0, -1 };

// 값 입력받는 함수
void input() {
	cin >> N >> M;
	cin >> Sy >> Sx >> Dir;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> Map[i][j];
		}
	}
}

// 문제풀이 함수
int solve() {

	int Cnt = 0;

	while (1) {

		// 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
		if (Map[Sy][Sx] == 0) {
			Cnt++;
			Map[Sy][Sx] = 2;
			continue;
		}

		int temp = Dir;

		int flag = 0;

		// 주변 4칸 체크 (반시계 방향으로)
		for (int i = 0; i < 4; i++) {

			Dir = (Dir + 3) % 4;

			int ny = Sy + diry[Dir];
			int nx = Sx + dirx[Dir];

			if (Map[ny][nx] == 0) {
				flag = 1;
				Sy = ny, Sx = nx;
				break;
			}

		}

		// 청소되지 않은 빈 칸이 없는 경우
		if (flag == 0) {
			Dir = (Dir + 2) % 4;
			int ny = Sy + diry[Dir];
			int nx = Sx + dirx[Dir];
			// 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
			if (Map[ny][nx] != 1) {
				Sy = ny, Sx = nx;
				Dir = temp;
			}

			// 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
			else {
				break;
			}
		}
	}

	return Cnt;
}

// 메인함수
int main() {

	// input
	input();

	// solve
	int Ans = solve();

	// output
	cout << Ans << "\n";
	
	return 0;
}

4. 문제 풀이를 마치며..

채점 결과

오랜만에 시뮬레이션, 구현 문제를 풀게되었다.

 

많은 학생들이 시뮬레이션 문제를 싫어하는데 그 이유는,

1) 문제가 보통 길다. 2) 코드가 길어질 수 밖에 없다. 3) 길어지고 정형화되어 있지 않은 만큼 디버깅이 어렵다.

이런 이유들이 있다.

 

시뮬레이션 문제의 핵심을 나는 침착하게 문제를 우선 다 읽고 상황을 이해한 뒤에 코드로 들어가는 것이라 생각한다.

그래야 실수가 나오지않고, 힘들게 디버깅하는 수고도 줄일 수 있다.

 

그렇게 정확히 읽고 이해한 정보들을 토대로 코드를 구현한다면 풀어낼 수 있을 것이다.