코딩 테스트 스터디/백준

[골드 V] 14503번. 로봇 청소기

남쪽마을밤송이 2022. 4. 5. 05:12

 문제 

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

 

14503번: 로봇 청소기

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어

www.acmicpc.net

 사용 언어 

Python3

 풀이 과정 

처음에 나는 d(현재 바라보고 있는 방향)에 따라서 다음 좌표값을 다르게 설정해주려 했는데, 그럼 왼쪽으로 회전할 때 뒤로 갈 때 등의 좌표값을 모두 조건문으로 나눠줘야 했다.

if d == 0: # 북쪽의 왼쪽
    next = (r, c-1)
elif d == 1: # 동쪽의 왼쪽
    next = (r-1, c)
elif d == 2: # 남쪽의 왼쪽
    next = (r, c+1)
elif d == 3: # 서쪽의 왼쪽
    next = (r+1, c)

if d == 0: # 북쪽의 뒤쪽
    next = (r+1, c)
elif d == 1: # 동쪽의 뒤쪽
    next = (r, c-1)
elif d == 2: # 남쪽의 뒤쪽
    next = (r-1, c)
elif d == 3: # 서쪽의 뒤쪽
    next = (r, c+1)

너무 비효율적인 것 같고 구현하다가 머리가 로봇청소기 마냥 빙빙 돌기도 해서 아쉽지만 다른 블로그를 참고했다.😥역시 델타값(?)을 사용하는 게 가장 깔끔한 것 같은데 아직 내가 코드에 적용하는게 어려운 것 같다.

dx = [-1,0,1,0]
dy = [0,1,0,-1]

구현 문제는 시간을 더~~~ 많이 두고 풀었으면 풀 수 있었을 지 모르나 그 시간에 다른 문제를 더 푸는게 좋다고 생각한다... 어쨌든 내가 수정할 부분은 수정해서 본 맞았습니다!! 시간이 생각보다 짧아서 신기했다.

+) 2022-04-08에 추가

스터디원의 코드리뷰를 참고하여 turnleft()함수를 그냥 while문 안으로 넣었더니 시간이 꽤 줄어들었다.

그리고 다른 곳에서 배운대로 % 연산자를 이용하여 20번째 줄도 수정했다.

수정한 코드는 아래 제출 답안에 반영해두었다.

 제출 답안 

import sys

N, M = map(int, sys.stdin.readline().strip().split())
r, c, d = map(int, sys.stdin.readline().strip().split())
coordinate = []
for _ in range(N):
    coordinate.append(list(map(int, sys.stdin.readline().strip().split())))
isVisited = [([False] * M) for _ in range(N)]
isVisited[r][c] = True # 현재 위치 방문

# 0: 위쪽 이동, 1: 오른쪽 이동, 2: 아래 이동, 3: 왼쪽 이동
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]

cleaned = 1 # 현재 위치 항상 청소하고 시작
turnTime = 0 # 왼쪽으로 회전한 횟수

while True:
    # 0 : 북, 1 : 동, 2 : 남, 3 : 서
    d = (d - 1) % 4 # 왼쪽으로 회전, -1 % 4 = 3
    nx = r + dx[d] # 회전한 방향으로 이동
    ny = c + dy[d] # 회전한 방향으로 이동
    
    if isVisited[nx][ny] == 0 and coordinate[nx][ny] == 0: # 이동을 했는데 방문하지 않았고 빈 공간인 경우
        isVisited[nx][ny] = True # 방문 처리
        cleaned += 1 # 청소 횟수 증가
        turnTime = 0 # 왼쪽 방향 회전 횟수 0으로 초기화
        r = nx # 위치 이동
        c = ny # 위치 이동
        continue # 반복
    else: # 이동이 불가능 한 경우 왼쪽 방향 회전 횟수만 증가
        turnTime += 1

    if turnTime == 4: # 총 4번 회전 한 경우, 네 방향 모두 청소가 되어 있거나 벽이 있는 경우
        nx = r - dx[d] # 뒤로 이동
        ny = c - dy[d] # 뒤로 이동

        if coordinate[nx][ny] == 0: # 이동한 위치가 벽이 아니라면
            r = nx # 이동
            c = ny # 이동
        else: # 그렇지 않으면
            break # 작동을 멈춤
        turnTime = 0 # 왼쪽 방향 회전 횟수 초기화

print(cleaned) # 청소 횟수 출력

 공부한 내용 

파이썬의 삼항연산자

최근에 자바스크립트를 사용하다 보니 습관적으로 ~?~:~ 형식으로 삼항연산자를 사용하려 했는데

파이썬은 좀 더 직관적이지 못한 삼항연산자 방식을 쓰는 것 같다. (항상 파이썬이 제일 직관적이라고 생각했는데 띠용)

어쨌든 이 방식도 익숙해지려고 해야겠다.

[true_value] if [condition] else [false_value] // 파이썬 방식

 

출처: https://m.blog.naver.com/wideeyed/221858874414 

음수에 % 연산자를 사용하면?

+) 2022-04-08에 추가

이 문제를 풀면서 -1이 3으로 초기화되어야 하는 상황에서 나는 삼항연산자를 사용했고, 그래서 위에 공부한 내용이라고도 써두었지만 알고보니 % 연산자를 사용하면 아주 간단히 해결될 문제였다.

음수에 %연산자를 사용해도 나머지는 0이나 자연수가 되어야 한다.

따라서

4 * (-1) + 3 = -1 // 몫 -1 나머지 3

150 * (-2) + 100 = -200 // 몫 -2 나머지 100

와 같이 나머지가 구해진다.

 

이를 음수일 경우 마지막 숫자로부터 초기화 되는 경우에 적용할 수 있다.