본문 바로가기

BOJ

BOJ 14503 로봇 청소기

정말 힘들게 구현했네요 이 망할 로봇청소기 ㅠㅠ

 

여러 번의 문제를 잘못 이해해서 있는 코드를 살짝 살짝 수정한 결과 굉장히 난잡한 코드가 됐습니다.

혹시나마 저 같은 사람이 있다면 조금이나마 도움이 되고자 글을 씁니다. (그리고 나중에 또 헷갈려할 나를 위해서..ㅎ)

 

 

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 위치를 청소한다.
  2. 현재 위치에서 현재 방향을 기준으로 왼쪽 방향부터 차례대로 인접한 칸을 탐색한다.
     a. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
     b. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
     c. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
     d. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

로봇 청소기는 이미 청소되어있는 칸을 또 청소하지 않으며, 벽을 통과할 수 없다.

 

잘못 이해한 해석. <2.c>

"바라보는 방향을 유지한 채로 한 칸 후진을 하고 ..." 이 부분을 지나왔던 부분을 즉, '과거의 좌표로' 돌아가는 줄 알았습니다. 하지만 말 그대로 '후진'을 하는 것이었네요..

그래서 재귀함수를 사용해서 사방 모두 이동할 수 없다면 함수를 빠져나와 원래의 좌표로 돌아오도록 구현을 하는 오류를 만들었죠ㅠㅠ

이 부분에서 꽤나 애를 먹었고 시간도 굉장히 많이 들었던 것 같습니다ㅠㅠ

 

코드는 남겨는 두는데 참 많이 부끄럽네요. 

저만 볼거니까 패스해주세요 ㅎㅎ...

 

그래도 저를 위해 간단한 정리를 하자면,

turn 함수로 사방의 청소되지 않은 방을 찾고 찾는다면 true를 리턴합니다.

방을 찾았다면 그곳으로 이동하고 다시 반복합니다.

방을 찾지 못하였다면(false를 리턴받음) 후진합니다. 그리고 다시 turn함수로 방을 찾습니다.

만약 후진하는 도중 벽을 만난다면 반복을 종료하고, 청소한 방의 개수를 출력합니다.

 

마무리가 애매하네요..

부족한 실력이지만 앞으로 같이 소통해요! 감사합니당!

코드


#include <iostream>
#include <vector>

using namespace std;

// 맵의 크기를 넘을 경우 예외 처리 함수 oversize()
bool oversize(int c, int r, vector<vector<int>> map)
{
	if (c >= map.size() || r >= map[0].size() || c < 0 || r < 0)
		return true;
	else
		return false;
}
bool turn(int c, int r, int& move_y, int& move_x, int& d, vector<vector<int>>& map, int &back_y, int& back_x)
{
	int cnt = 0;				// 사방이 막혀있는지 확인용 변수
	move_x = 0, move_y = 0;		// 초기화

	d = (d + 4 - 1) % 4;		// 방향 회전

	while (cnt != 4)
	{
		switch (d)
		{
		// 북쪽
		case 0:
			// 맵의 크기를 넘을 경우 예외 처리 함수 oversize()
			if (!oversize(c - 1, r, map))
			{
				if (map[c - 1][r] == 0)
				{
					move_y = -1;
					return true;
				}
			}

			d = (d + 4 - 1) % 4;	// 그 방향에서의 왼쪽
			back_x = 0;
			back_y = 1;
			cnt++;

			break;
		// 동쪽
		case 1:
			if (!oversize(c, r + 1, map))
			{
				if (map[c][r + 1] == 0)
				{
					move_x = 1;
					return true;
				}
			}

			d = (d + 4 - 1) % 4;	// 그 방향에서의 왼쪽
			back_x = -1;
			back_y = 0;
			cnt++;

			break;
		// 남쪽
		case 2:
			if (!oversize(c + 1, r, map))
			{
				if (map[c + 1][r] == 0)
				{
					move_y = 1;
					return true;
				}
			}

			d = (d + 4 - 1) % 4;	// 그 방향에서의 왼쪽	
			back_x = 0;
			back_y = -1;
			cnt++;

			break;
		// 서쪽
		case 3:
			if (!oversize(c, r - 1, map))
			{
				if (map[c][r - 1] == 0)
				{
					move_x = -1;
					return true;
				}
			}

			d = (d + 4 - 1) % 4;	// 그 방향에서의 왼쪽	
			back_x = 1;
			back_y = 0;
			cnt++;

			break;
		}
	}

	d = (d + 4 + 1) % 4;		// 한 번 더 돌았으므로 조건 2.c를 만족하기 위해 반대로 한 번 돌아준다.

	return false;
}

int main()
{
	int n, m;		// 세로(n)와 가로(m)
	cin >> n >> m;
	int r, c, d;
	cin >> c >> r >> d;
	vector<vector<int>> map;

	// map 입력
	for (int i = 0; i < n; i++)
	{
		vector<int> v(0, 0);
		for (int j = 0; j < m; j++)
		{
			int num;
			scanf("%d", &num);
			v.push_back(num);
		}
		map.push_back(v);
	}

	map[c][r] = 2;
	int clean_n = 1;				// 청소한 방의 개수

	int move_x = 0, move_y = 0;		// 이동할 거리
	int back_x = 0, back_y = 0;	// 후진할 좌표를 알려줌.
	
	// 사방이 막혔고 뒤가 벽이라면 동작을 멈춘다.
	while (map[c][r] != 1)
	{
		// 회전할 수 있다면(= 이동할 수 있다면)
		if (turn(c, r, move_y, move_x, d, map, back_y, back_x))
		{
			// 이동한다.
			c += move_y;
			r += move_x;

			map[c][r] = 2;
			clean_n++;
		}
		// 사방이 막혀있거나 청소되어 있다면
		else
		{
			// 후진한다.
			if (!oversize(c + back_y, r + back_x, map))
			{
				c += back_y;
				r += back_x;
			}
			// 후진을 하면 맵에서 벗어나므로 동작 종료.
			else
				break;
		}
	}

	cout << clean_n << endl;

}

'BOJ' 카테고리의 다른 글

[BOJ] 2178 미로탐색 (feat. bfs 알고리즘)  (0) 2021.08.23