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

이성훈·2021년 11월 16일
0
post-custom-banner

문제

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

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

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

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

입력

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

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

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

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

출력

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

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

풀이

처음에는 문제에서 정해진 a~ d를 하나씩 함수로 구현해서 하려니, 중복되는 경우가있어서 결국에 robot()하나의 함수에 모든과정을 반복시켰다.
먼저 방향(변수 d)을 바꾸는 함수 cd() 를 정의하여 0, 3, 2, 1, 0 ,3 ,... 순으로 바뀌게한다.
while(true)로 무한루프돌리면서,
매회 int dir = cd(d); 로 현재 방향에서 왼쪽으로 튼방향값을 dir에 저장
이위치의 다음값이 어떤값인지를 보여주는 next함수를 정의하여
0 (빈공간)을 만나게되면 실제로 청소기위치를 바꾸는 move함수를 실행시킨다.
설명하자니 너무 장황해서 코드에 주석으로 설명을 남기겠다.
딱히 수학적인 과정이나 논리적과정없이 구현만으로도 해결할 수 있었다.

#define _CRT_SECURE_NO_WARNINGS 
#include <bits/stdc++.h>
using namespace std;
int N, M, **house;
int r, c, d; //로봇위치,  방향 0)북 1)동 2)남 3)서
/*
0 : 청소하지않은공간
1 : 벽
2 : 청소함
*/
void clean(); //함수원형들
int cd(int dir);
int next(int dir);
void move(int dir);
bool f();

void clean() { //현재 로봇위치를 청소
	if (house[r][c] != 2) {
		house[r][c] = 2; 
	}
}

bool f() { //사방이 전부 막혔는가
	if(next(d) != 0 &&
		next(cd(d)) != 0 &&
		next(cd(cd(d))) != 0 &&
		next(cd(cd(cd(d)))) != 0) {
		return true;
	}
	return false;
}

int cd(int dir) { //방향전환(반시계방향으로-왼쪽)
	dir--;
	if (dir == -1) dir = 3;
	return dir;
}
//dir방향 1칸앞에 무엇이있는가
int next(int dir) { 
	//0) 청소하지않은공간
	//1) 벽(이동불가, 배열범위를벗어난경우도 포함)
	//2) 청소한공간
	int now_r = r, now_c = c;
	if (dir == 0) {
		now_r--; //북
	}
	else if (dir == 1) {
		now_c++; //동
	}
	else if (dir == 2) {
		now_r++; //남
	}
	else if (dir == 3) {
		now_c--; //서
	}
	if (now_r < 0 || now_r == N ||
		now_c < 0 || now_c == M) {
		return 1; //이동불가능한곳은 벽으로생각함
	}
	return house[now_r][now_c]; //상태(0,1,2)를 출력
}

//실제로 dir방향으로 움직이는 함수
void move(int dir) { 
	int now_r = r, now_c = c;
	if (dir == 0) {
		now_r--; //북
	}
	else if (dir == 1) {
		now_c++; //동
	}
	else if (dir == 2) {
		now_r++; //남
	}
	else if (dir == 3) {
		now_c--; //서
	}
	r = now_r; //실제위치 기록
	c = now_c;
}

void robot() {
	while (true) {
		clean(); //현재위치청소

		int dir = cd(d); //왼쪽으로 한번돈다.
		if (next(dir) == 0) {
			//청소하지않은공간이라면
			move(dir);
			d = dir;
			continue;
		}

		if (f()) { //사방이막힌경우
			dir = cd(cd(d)); //두번돌리면 후진방향
			if (next(dir) == 1) {
				//뒤가 벽이었다면 후진불가하니 종료
				return;
			}
			else {
				//후진가능하면
				move(dir); //후진
				continue;
			}
		}
		//벽이나 청소한곳이라면 방향만전환
		d = dir;
	}
}

void printAll() { //청소한 총 면적을 출력
	int res=0;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
			if (house[i][j] == 2)
				res++;
	printf("%d", res);
}

int main(void) {
	scanf("%d%d", &N, &M);

	house = new int*[N];
	for (int i = 0; i < N; i++)
		house[i] = new int[M]; //맵생성

	scanf("%d%d%d", &r, &c, &d);
	for(int i = 0 ; i < N ; i++) //맵기록
		for (int j = 0, temp=0; j < M; j++) {
			scanf("%d", &temp);
			house[i][j] = temp;
		}
	robot();

	printAll();
	return 0;
}
profile
I will be a socially developer
post-custom-banner

0개의 댓글