Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[백준] 16930번 달리기 본문

코딩테스트/Python 문제풀기

[백준] 16930번 달리기

끈기JK 2025. 2. 5. 22:17

달리기

시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율
1 초 512 MB 8830 1303 839 13.213%

문제

진영이는 다이어트를 위해 N×M 크기의 체육관을 달리려고 한다. 체육관은 1×1 크기의 칸으로 나누어져 있고, 칸은 빈 칸 또는 벽이다. x행 y열에 있는 칸은 (x, y)로 나타낸다.

매 초마다 진영이는 위, 아래, 오른쪽, 왼쪽 중에서 이동할 방향을 하나 고르고, 그 방향으로 최소 1개, 최대 K개의 빈 칸을 이동한다.

시작점 (x1, y1)과 도착점 (x2, y2)가 주어졌을 때, 시작점에서 도착점으로 이동하는 최소 시간을 구해보자.

입력

첫째 줄에 체육관의 크기 N과 M, 1초에 이동할 수 있는 칸의 최대 개수 K가 주어진다.

둘째 줄부터 N개의 줄에는 체육관의 상태가 주어진다. 체육관의 각 칸은 빈 칸 또는 벽이고, 빈 칸은 '.', 벽은 '#'으로 주어진다.

마지막 줄에는 네 정수 x1, y1, x2, y2가 주어진다. 두 칸은 서로 다른 칸이고, 항상 빈 칸이다.

출력

(x1, y1)에서 (x2, y2)로 이동하는 최소 시간을 출력한다. 이동할 수 없는 경우에는 -1을 출력한다.

제한

  • 2 ≤ N, M ≤ 1,000
  • 1 ≤ K ≤ 1,000
  • 1 ≤ x1, x2 ≤ N
  • 1 ≤ y1, y2 ≤ M

예제 입력 1

3 4 4
....
###.
....
1 1 3 1

예제 출력 1

3

예제 입력 2

3 4 1
....
###.
....
1 1 3 1

예제 출력 2

8

예제 입력 3

2 2 1
.#
#.
1 1 2 2

예제 출력 3

-1

내 코드

시간 초과

from collections import deque

DIRECTIONS = [(0, -1), (0, 1), (-1, 0), (1, 0)]  # 상하좌우 방향

def get_minimum_time(N, M, K, gym, x1, y1, x2, y2):
    queue = deque([(x1, y1)])
    gym[y1][x1] = 0  # 첫 위치 방문처리

    while queue:
        x, y = queue.popleft()

        for dx, dy in DIRECTIONS:

            # 1부터 K까지 확인
            for k in range(1, K + 1):
                nx, ny = x + (dx * k), y + (dy * k)

                # 이동 범위인지 확인
                if 0 <= nx < M and 0 <= ny < N:

                    # 벽(#) 있으면 다음 방향
                    if gym[ny][nx] == '#':
                        break

                    # .이면 이동 시간 입력
                    if gym[ny][nx] == '.':
                        gym[ny][nx] = gym[y][x] + 1

                        # 도착 확인
                        if (nx, ny) == (x2, y2):
                            return gym[ny][nx]

                        # 도착 아니면 이동한 위치 큐에 추가
                        queue.append((nx, ny))

    return -1  # 큐가 비면 도달 불가이므로 -1 리턴

N, M, K = map(int, input().split())  # 세로, 가로, 최대이동칸수
gym = [list(input()) for _ in range(N)]
y1, x1, y2, x2 = map(int, input().split())

print(get_minimum_time(N, M, K, gym, x1 - 1, y1 - 1, x2 - 1, y2 - 1))

chatGPT

from collections import deque

def min_time_to_reach(N, M, K, gym, start, end):
    x1, y1 = start
    x2, y2 = end

    # 방향 벡터 (상, 하, 좌, 우)
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

    # BFS 초기화
    queue = deque([(x1 - 1, y1 - 1)])  # (행, 열)
    visited = [[-1] * M for _ in range(N)]
    visited[x1 - 1][y1 - 1] = 0

    while queue:
        x, y = queue.popleft()
        time = visited[x][y]

        # 도착점에 도달하면 최소 시간 반환
        if (x, y) == (x2 - 1, y2 - 1):
            return time

        # 4방향으로 최대 K칸 이동 가능
        for dx, dy in directions:
            for step in range(1, K + 1):
                nx, ny = x + dx * step, y + dy * step

                # 범위 벗어나거나 벽 만나면 중단
                if not (0 <= nx < N and 0 <= ny < M) or gym[nx][ny] == '#':
                    break

                # 아직 방문하지 않았거나 더 빠른 시간에 도달할 경우 갱신
                if visited[nx][ny] == -1:
                    visited[nx][ny] = time + 1
                    queue.append((nx, ny))
                elif visited[nx][ny] <= time:
                    break  # 불필요한 탐색 방지

    return -1  # 도달 불가능

# 입력 처리
N, M, K = map(int, input().split())
gym = [list(input().strip()) for _ in range(N)]
x1, y1, x2, y2 = map(int, input().split())
print(min_time_to_reach(N, M, K, gym, (x1, y1), (x2, y2)))
  1. 입력 처리:
    • 먼저 체육관의 크기(N, M), 한 번에 이동할 수 있는 최대 칸 수(K), 그리고 체육관 상태(gym)를 입력받습니다.
    • 시작점과 목표점의 좌표도 입력받습니다. 입력된 좌표는 1-indexed이므로, 이를 0-indexed로 변환하여 사용합니다.
  2. 방향 설정:
    • 이동할 수 있는 4가지 방향(상, 하, 좌, 우)을 directions 배열로 설정합니다. 이 배열을 사용하여 각 칸에서 이동할 수 있는 방향을 계산합니다.
  3. BFS 탐색 초기화:
    • BFS를 위한 큐(queue)를 준비합니다. 큐에는 현재 위치와 해당 위치에 도달한 시간을 저장합니다.
    • visited 배열은 각 칸에 도달한 최소 시간을 기록하는 배열입니다. 시작점은 0초에 방문했으므로 visited 배열에서 시작점의 값을 0으로 설정합니다.
  4. BFS 탐색 진행:
    • 큐에서 하나씩 위치를 꺼내며 탐색을 진행합니다. 각 위치에서 4방향으로 최대 K칸까지 이동할 수 있습니다.
    • 이동할 수 있는 칸에 대해 범위 체크와 벽 여부를 확인하여, 이동할 수 있다면 그 칸을 큐에 넣고 방문 시간을 갱신합니다.
    • 만약 목표 지점에 도달하면, 해당 시간(이동 횟수)을 즉시 반환합니다.
  5. 불가능한 경우 처리:
    • 큐에 더 이상 방문할 수 있는 위치가 없으면 목표 지점에 도달할 수 없다는 의미이므로, 1을 반환하여 도달 불가능함을 나타냅니다.

최종적으로:

  • 이 코드는 BFS를 사용하여 가장 빠르게 목표 지점에 도달하는 경로를 구합니다.
  • 이동을 최적화하기 위해, 한 번에 최대 K칸까지 이동을 허용하며, 벽과 범위 체크를 통해 유효한 경로만 탐색합니다.

부가 질문

내 생각

  1. K 까지 step 이동, 시간을 저장하는 배열까지 생각했으나, 시간이 초과된 것을 만나면 break 하는 것을 생각하지 못했다.

'코딩테스트 > Python 문제풀기' 카테고리의 다른 글

[백준] 13460번 구슬 탈출 2  (0) 2025.02.07
[백준] 17086번 아기 상어 2  (0) 2025.02.04
[백준] 14226번 이모티콘  (0) 2025.02.02
[백준] 13913번 숨바꼭질 4  (0) 2025.01.31
[백준] 13549번 숨바꼭질3  (0) 2024.11.23