본문 바로가기
알고리즘 문제풀이/삼성역량테스트

[삼성역량테스트] 14503 로봇청소기

by 로디네로 2021. 1. 3.
반응형

 

풀이일시 : 2020-10-17

 

문제 :

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.

로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다. 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북중 하나이다. 지도의 각 칸은 (r, c)로 나타낼 수 있고, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로 부터 떨어진 칸의 개수이다.

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

1. 현재 위치를 청소한다.

2. 현재 위치에서 현재 방향을 기준으로 왼쪽방향부터 차례대로 탐색을 진행한다.

a. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.

b. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.

c. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.

d. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

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

입력 :

첫째 줄에 세로 크기 N(행)과 가로 크기 M(열)이 주어진다. (3 ≤ N, M ≤ 50)

둘째 줄에 로봇 청소기가 있는 칸의 좌표 (r, c)와 바라보는 방향 d가 주어진다. d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우에는 서쪽을 바라보고 있는 것이다.

셋째 줄부터 N개의 줄에 장소의 상태가 북쪽부터 남쪽 순서대로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 빈 칸은 0, 벽은 1로 주어진다. 지도의 첫 행, 마지막 행, 첫 열, 마지막 열에 있는 모든 칸은 벽이다.

로봇 청소기가 있는 칸의 상태는 항상 빈 칸이다.

ex)

3 3 //행열

1 1 0 //있는 위치 (1,1) 방향(0:북쪽)

1 1 1 //벽은 1

1 0 1

1 1 1

출력 :

로봇 청소기가 청소하는 칸의 개수를 출력한다.

ex)

1

풀이 :

dfs를 이용하여 풀이해준다.

 

- map을 생성해준 뒤 dfs를 (행,열,방향) 을 넣어 실행시켜준다.

 

- dfs에서는 그 좌표를 방문하지 않았고 이동할수있는 0 이라면 cnt++ 해주고 2로 만든다( 1은 벽이므로)

 

- 이후 방향에 따라 좌표를 재정의함으로써 이동시켜준다. 만약 범위를 넘는다면 continue하고 이동한 곳이 이동할 수 있는곳이고 아직 이동하지 않았다면 (0 상태라면) 그곳에서 다시 새로운 좌표로 dfs 재귀를 넣는다.

 

- 청소를 모두완료했거나 벽이면서 뒤쪽도 벽이라 후진도 못하면 return으로 끝내고, 후진을 할수있다면 방향을 유지한채로 후진한다.

 

#include <iostream>
#include <stdio.h>
using namespace std;

int n, m, cnt = 0;
int map[50][50];
int nexty[4] = { -1, 0, 1, 0 };
int nextx[4] = { 0, 1, 0, -1 };
int backy[4] = { 1, 0, -1, 0 };
int backx[4] = { 0, -1, 0, 1 };

void dfs(int y, int x, int d) {
	int k;
	if (map[y][x] == 0) {
		cnt++;
		map[y][x] = 2;
	}
	for (k = d - 1; k > d - 5; k--) {
		int newk = (k + 4) % 4;
		int newy = y + nexty[newk];
		int newx = x + nextx[newk];
		if (newy < 0 || newy > n - 1 || newx < 0 || newx > m - 1)
            continue;
		if (map[newy][newx] == 0) {
			dfs(newy, newx, newk);
			return;
		}
	}
	if (map[y + backy[d]][x + backx[d]] == 1) return;
	else dfs(y + backy[d], x + backx[d], d);
}

int main() {
	int r, c, d, i, j;
	cin >> n >> m;
	cin >> r >> c >> d;

	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			cin >> map[i][j];
		}
	}
	dfs(r, c, d);
	printf("%d\n", cnt);
	return 0;
} 

처음에는 dfs를 통한 구현을 해내지 못했다. 하지만 문제가 나오면 어떻게든 풀어야 되지 않겠나 싶어 어떻게든 구현해보았다.

바로 아래의 코드이다. 아래의 코드를 보면 dfs를 공부해야겠다는 생각이 들것이다.

 

#include <iostream>
using namespace std;
int map[51][51] = { 0, };// 방문한곳을 1로바꾸면 곧 visit
int cnt = 0;
void cleaner(int x, int y, int d) {
	//주위가 다막힐때까지 반복한다
	while (1) { 
		if (map[x][y] == 0) {
			map[x][y] = 2;
			cnt++;
		}
		
		if (d == 0) {
			if ((map[x + 1][y] == 1) && map[x - 1][y] && map[x][y - 1] && map[x][y + 1]) { //뒤가 확실히 벽
				break;
			}
			else if (map[x + 1][y] && map[x - 1][y] && map[x][y - 1] && map[x][y + 1]) { //후진가능
				x++; //다 1,2이지만 뒤가 벽(1)이 아니라면 후진한다.
			}
			else if(map[x][y-1]) { //서쪽에 청소공간없다면
				d = 3;// 서쪽으로 회전
				//2번으로 돌아간다?? continue?
			}
			else if (map[x][y - 1] == 0) { //서쪽에 청소공간이있다면
				d = 3; //서쪽으로 회전
				y--; //서쪽으로 한칸 전진
				continue; //break와 continue의 차이 break는 반복문을 탈출하지만 continue는 반복문 처음으로돌아감
			}
		}
		else if (d == 1) {
			if (map[x + 1][y] && map[x - 1][y] && (map[x][y - 1] == 1) && map[x][y + 1]) { //뒤가 확실히 벽
				break;
			}
			else if (map[x + 1][y] && map[x - 1][y] && map[x][y - 1] && map[x][y + 1]) { //후진가능
				y--; //뒤가 벽(1)이 아니라면 후진한다.
			}
			else if (map[x - 1][y]) { //서쪽에 청소공간없다면
				d = 0;// 서쪽으로 회전
				//2번으로 돌아간다?? continue?
			}
			else if (map[x-1][y] == 0) { //서쪽에 청소공간이있다면
				d = 0; //서쪽으로 회전
				x--; //서쪽으로 한칸 전진
				continue; //break와 continue의 차이 break는 반복문을 탈출하지만 continue는 반복문 처음으로돌아감
			}
		}
		else if (d == 2) {
			if (map[x + 1][y] && (map[x - 1][y] == 1) && map[x][y - 1] && map[x][y + 1]) { //뒤가 확실히 벽
				break;
			}
			else if (map[x + 1][y] && map[x - 1][y] && map[x][y - 1] && map[x][y + 1]) { //후진가능
				x--; //뒤가 벽(1)이 아니라면 후진한다.
			}
			else if (map[x][y + 1]) { //서쪽에 청소공간없다면
				d = 1;// 서쪽으로 회전
				//2번으로 돌아간다?? continue?
			}
			else if (map[x][y+1] == 0) { //서쪽에 청소공간이있다면
				d = 1; //서쪽으로 회전
				y++; //서쪽으로 한칸 전진
				continue; //break와 continue의 차이 break는 반복문을 탈출하지만 continue는 반복문 처음으로돌아감
			}
		}
		else {
			if (map[x + 1][y] && map[x - 1][y] && map[x][y - 1] && (map[x][y + 1] == 1)) { //뒤가 확실히 벽
			break;
			}
			else if (map[x + 1][y] && map[x - 1][y] && map[x][y - 1] && map[x][y + 1]) { //후진가능
			y++; //뒤가 벽(1)이 아니라면 후진한다.
			}
			else if (map[x+1][y]) { //서쪽에 청소공간없다면
			d = 2;// 서쪽으로 회전
			//2번으로 돌아간다?? continue?
			}
			else if (map[x+1][y] == 0) { //서쪽에 청소공간이있다면
				d = 2; //서쪽으로 회전
				x++; //서쪽으로 한칸 전진
				continue; //break와 continue의 차이 break는 반복문을 탈출하지만 continue는 반복문 처음으로돌아감
			}
			
		}
	}
}
/*
보는 방향에 따른 이동
0(바라보고있는 위치가 북) :앞(-1,0) 오른(0,1) 뒤(1,0) 왼(0,-1)
1(바라보고있는 위치가 동) :앞(0,1) 오른(1,0) 뒤(0,-1) 왼(-1,0) 
2(바라보고있는 위치가 남) :앞(1,0) 오른(0,-1) 뒤(-1,0) 왼(0,1)
3(바라보고있는 위치가 서) :앞(0,-1) 오른(-1,0) 뒤(0,1) 왼(1,0)
*/
int main() {
	int N, M;
	cin >> N >> M;
	int r, c, d; //로봇청소기의 좌표, 바라보고있는방향
	cin >> r >> c >> d;
	for (int i = 0; i < N; i++) { //가로
		for (int j = 0; j < M; j++) { //세로
			cin >> map[i][j];
		}
	}
	cleaner(r, c, d);
	cout << cnt << endl;
	return 0;
}

 

참고자료 : map container

dbstndi6316.tistory.com/29

 

[개념정리] map container

map container란 key와 value가 쌍으로 저장되는 노드기반 이진트리구조 container이다. 이에 반해 vector는 key없이 value만 list형태로 저장된다. key는 고유한 값이므로 중복이 불가능하다. 삽입이 되면서 자

dbstndi6316.tistory.com

참고자료 : DFS

dbstndi6316.tistory.com/64

 

[기본문제풀이] DFS 깊이우선탐색

풀이일시 : 2020-08-30 ​ DFS : 깊이우선탐색으로 DFS보다 좁고 깊게 탐색해나가며 전체 정점을 탐색하는 방법이다. 주로 stack을 이용한다. 아래그림이 dfs를 한눈에 보여준다고 생각한다 출처 : http://

dbstndi6316.tistory.com

 

반응형

댓글