알고리즘/문제풀이

[백준] 14503번 로봇청소기 - 파이썬(Python)

SeongOnion 2021. 10. 3. 12:18
728x90

문제 (링크)

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

 

14503번: 로봇 청소기

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

www.acmicpc.net

 

나의 풀이

import sys
input = sys.stdin.readline

n, m = map(int, input().split())
current_x, current_y, d = map(int, input().split())
# d : 북 - 0, 동 - 1, 남 - 2, 서 - 3
graph = []
for _ in range(n):
    graph.append(list(map(int, input().split())))

moves = [
    [-1, 0], # 북쪽 방향으로 한 칸 이동
    [0, 1], # 동쪽 방향으로 한 칸 이동
    [1, 0], # 남쪽 방향으로 한 칸 이동
    [0, -1] # 서쪽 방향으로 한 칸 이동
]

# current_x + moves[d][0], current_y + moves[d][1] -> 현재 바라보고 있는 방향으로 한 칸 이동

# 시작점 청소한 것으로 업데이트
ans = 1
graph[current_x][current_y] = 2

def clean_here(current_x, current_y):
    global ans
    # 벽과 구분하기 위해서 청소된 구역은 2로 업데이트
    graph[current_x][current_y] = 2

    ans += 1

def turn_left(current_direction):
    if current_direction == 0:
        return 3
    
    else:
        return current_direction - 1


def is_cleanable(current_x, current_y, current_d):
    """
    현재 바라보고 있는 위치가 청소 가능한지 확인하는 함수
    """
    temp_x = current_x + moves[current_d][0]
    temp_y = current_y + moves[current_d][1]

    if 0 <= temp_x < n and 0 <= temp_y < m:
        if graph[temp_x][temp_y] == 0:
            return True
    
    return False

in_loop = True

while in_loop:
    for i in range(4):
        # 청소 할 수 있든 없든 회전은 하기 때문에 회전 먼저 해줌
        d = turn_left(d)
        
        # 만약 현재 바라보고 있는 위치가 청소 가능하다면
        if is_cleanable(current_x, current_y, d):
            # 한 칸 전진
            current_x += moves[d][0]
            current_y += moves[d][1]

            # 현 위치 청소
            clean_here(current_x, current_y)

            # 청소 후에는 다시 처음으로 돌아가므로 break
            break
        
        # 바라보고 있는 위치가 청소 불가능하다면 반복문 계속 진행
        else:
            continue
    
    # for문이 break 없이 종료되었다면 (네 방향 모두 청소 불가능하다면)
    else:
        # 뒤로 이동 -> 2바퀴 회전 후 이동하는 것과 같음 (실제 방향은 업데이트 X)
        temp_d = turn_left(d)
        temp_d = turn_left(temp_d)

        temp_x = current_x + moves[temp_d][0]
        temp_y = current_y + moves[temp_d][1]
        
        # 현재 위치의 뒷 방향이 범위 내에 있으면서 벽이 아닐 때 
        if 0 <= temp_x < n and 0 <= temp_y < m and graph[temp_x][temp_y] != 1:
            # 뒤로 한 칸 이동
            current_x = temp_x
            current_y = temp_y
        
        # 뒤로 이동할 수 없을 때
        else:
            in_loop = False

print(ans)

코드 설명 및 풀이법

문제에 나와있는 조건만 충실하게 구현해주면 되는 문제였지만 이게 말하는 것만큼 쉽지만은 않았다.

 

보통 구현 문제는 코드를 짜다가 스스로 길을 잃었던 경험이 많아서, 최대한 간결하고 함수로 나눌 수 있다고 생각한 것들은 최대한 나누려고 했다.

 

이를 위해서 청소하기, 왼쪽으로 회전하기, 현재 바라보는 방향이 청소 가능한지 확인하기, 이렇게 3가지를 함수로 뺐다.

 

2차원 배열에서 움직이기 위해서 상하좌우 움직임을 기록해놓은 moves의 인덱스를 입력값의 방향인 d와 대응시켜 만들어주었다.