본문 바로가기
문제 해결/BOJ

[백준] 로봇

by 자잘 2023. 4. 19.

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

 

1726번: 로봇

많은 공장에서 로봇이 이용되고 있다. 우리 월드 공장의 로봇은 바라보는 방향으로 궤도를 따라 움직이며, 움직이는 방향은 동, 서, 남, 북 가운데 하나이다. 로봇의 이동을 제어하는 명령어는

www.acmicpc.net

1. 문제 이해

로봇을 움직일 때 명령어가 한번 수행됩니다. 1 ~ 3만큼 이동시킬 수 있는 Go K 명령어와 왼쪽, 오른쪽으로 90도 만큼 움직일 수 있는 Turn dir 명령어가 있습니다. 출발지점과 현재 바라보는 방향에서 출발하여 도착지점에서 주어진 방향으로 바라볼 수 있기 위해 필요한 최소 명령어를 출력하면 됩니다.

2. 문제 접근

첫번째 접근: BFS

3차원 dist 배열과 heap을 사용한 BFS를 떠올릴 수 있었습니다. 각각의 위치에서 바라보고 있는 방향에 따라 필요한 명령어의 개수가 다르기 때문에 3차원 배열을 사용하였고 거리가 아닌 명령어가 항상 최소가 되어야하기에 heap을 사용하였습니다. 

3. 풀이

import sys, heapq
#sys.stdin = open("input.txt", "r")

input = sys.stdin.readline
# m: 세로, n: 가로 길이
m, n = tuple(map(int, input().split()))

board = [
    list(map(int, input().split()))
    for _ in range(m)
]

startY, startX, startDir = tuple(map(int, input().split()))
startY -= 1
startX -= 1
startDir -= 1

endY, endX, endDir = tuple(map(int, input().split()))
endY -= 1
endX -= 1
endDir -= 1

# 동, 서, 남 북
dys = [0, 0, 1, -1]
dxs = [1, -1, 0, 0]

q = [(0, startY, startX, startDir)]

# dist[dir][y][x]: y,x에 dir 방향으로 오는데 필요한 최소 거리
dist = [
    [[10000000 for _ in range(n)]
     for __ in range(m)]
    for ___ in range(4)
]

dist[startDir][startY][startX] = 0


def turnRignt(dir):
    if dir == 0:
        return 2
    elif dir == 1:
        return 3
    elif dir == 2:
        return 1
    else:
        return 0

def turnLeft(dir):
    if dir == 0:
        return 3
    elif dir == 1:
        return 2
    elif dir == 2:
        return 0
    else:
        return 1

def inRange(y, x):
    return 0 <= y < m and 0 <= x < n

while q:
    cnt, y, x, dir = heapq.heappop(q)

    # print("y : ", y, " x: ", x, " dir: ", dir, " cnt: ", cnt)
    if y == endY and x == endX and dir == endDir:
        print(cnt)
        break

    if dist[dir][y][x] < cnt:
        continue

    # go K를 수행
    for k in range(1, 4):
        temp = 0

        isOutOfRange = False
        ny = y
        nx = x

        while temp < k:
            ny += dys[dir]
            nx += dxs[dir]

            # 격자범위를 넘어가거나 갈 수 없는 지역인 경우
            if not inRange(ny, nx) or board[ny][nx] == 1:
                isOutOfRange = True
                break

            temp += 1


        if not isOutOfRange and dist[dir][ny][nx] > cnt + 1:
            dist[dir][ny][nx] = cnt + 1
            heapq.heappush(q, (cnt + 1, ny, nx, dir))


    # turn right을 수행해본다.
    nextDir = turnRignt(dir)

    if dist[nextDir][y][x] > cnt + 1:
        dist[nextDir][y][x] = cnt + 1
        heapq.heappush(q, (cnt + 1, y, x, nextDir))

    # turn left를 수행해본다.
    nextDir = turnLeft(dir)
    if dist[nextDir][y][x] > cnt + 1:
        dist[nextDir][y][x] = cnt + 1
        heapq.heappush(q, (cnt + 1, y, x, nextDir))

4. 회고

이 문제에서 제가 놓쳤던 부분은 한번에 2, 3 거리만큼 이동할 수 있는데 그 사이에 벽이 있는 경우에는 이동할 수가 없습니다. 이를 체크하는 것을 놓쳐서 푸는데 시간이 걸렸습니다.

'문제 해결 > BOJ' 카테고리의 다른 글

[백준] 내리막 길  (0) 2023.04.21
[백준] 택배  (0) 2023.04.20
[백준] ACM Craft  (0) 2023.04.18
[백준] 우주신과의 교감  (0) 2023.04.18
[백준] 수확  (0) 2023.04.17