Baekjoon

[Baekjoon] 배열에서 이동(python)

김철현 2022. 10. 9. 22:22

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

문제 접근

풀이 방법이 떠오르지 않아 문제의 알고리즘 힌트와 질문 검색을 통해 문제를 해결하였다.

 

이 문제는 이분탐색 + BFS로 해결할 수 있다.

 

최댓값과 최솟값의 차이를 이분탐색을 통해 찾고 BFS를 통해 그 값이 가능한지 탐색하면 된다.


풀이 과정

이분 탐색을 통해 가능한 값을 찾는 것이 핵심!

while left <= right:
    mid = (left + right) // 2

    if is_available(mid):
        right = mid - 1
        answer = min(answer, mid)
    else:
        left = mid + 1

print(answer)

 

그 다음 해당 차이값으로 (0, 0)에서 (n-1, n-1)까지 탐색할 수 있는지 검사하는 함수를 작성한다.

 

이분탐색을 통해 차이값을 얻었기 때문에 범위를 지정해야 한다.

 

범위의 시작은 배열의 최솟값이고 최솟값 + 차이값이 배열의 최댓값을 넘기지 않으면 범위의 끝으로 지정할 수 있다.

def is_available(difference):
    for i in range(min_val, max_val - difference + 1):
        start, end = i, i + difference

        # 첫번째 칸이 범위를 벗어나는지 먼저 체크
        if arry[0][0] < start or arry[0][0] > end:
            continue

        if bfs(start, end):
            return True

    return False

 

마지막으로 BFS를 통해 (0, 0)에서 (n-1, n-1)까지 도달할 수 있는지 검사하면 된다.

def bfs(start, end):
    dx = [-1, 0, 0, 1]
    dy = [0, -1, 1, 0]
    visited = [[False] * n for _ in range(n)]

    q = deque()

    q.append([0, 0])
    visited[0][0] = True

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

        if x == n - 1 and y == n - 1:
            return True

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if (
                nx < 0
                or nx >= n
                or ny < 0
                or ny >= n

                # 다음 칸이 범위에 벗어나면 탐색하지 않는다
                or arry[nx][ny] < start
                or arry[nx][ny] > end
                or visited[nx][ny]
            ):
                continue

            q.append([nx, ny])
            visited[nx][ny] = True

    return False

정답 코드

"""
    백준 1981번 배열에서 이동
"""
import sys
from collections import deque


def is_available(difference):
    for i in range(min_val, max_val - difference + 1):
        start, end = i, i + difference

        # 첫번째 칸이 범위를 벗어나는지 먼저 체크
        if arry[0][0] < start or arry[0][0] > end:
            continue

        if bfs(start, end):
            return True

    return False


def bfs(start, end):
    dx = [-1, 0, 0, 1]
    dy = [0, -1, 1, 0]
    visited = [[False] * n for _ in range(n)]

    q = deque()

    q.append([0, 0])
    visited[0][0] = True

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

        if x == n - 1 and y == n - 1:
            return True

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if (
                nx < 0
                or nx >= n
                or ny < 0
                or ny >= n

                # 다음 칸이 범위에 벗어나면 탐색하지 않는다
                or arry[nx][ny] < start
                or arry[nx][ny] > end
                or visited[nx][ny]
            ):
                continue

            q.append([nx, ny])
            visited[nx][ny] = True

    return False


n = int(sys.stdin.readline())
arry = []
for _ in range(n):
    arry.append(list(map(int, sys.stdin.readline().split())))


min_val = sys.maxsize
max_val = -1


for i in range(n):
    for j in range(n):
        min_val = min(min_val, arry[i][j])
        max_val = max(max_val, arry[i][j])


left = 0
right = max_val - min_val
answer = max_val

while left <= right:
    mid = (left + right) // 2

    if is_available(mid):
        right = mid - 1
        answer = min(answer, mid)
    else:
        left = mid + 1

print(answer)

'Baekjoon' 카테고리의 다른 글

[Baekjoon] 로고(python)  (0) 2022.10.17
[Baekjoon] 파일 합치기(python)  (0) 2022.10.17
[Baekjoon] 로봇 청소기(python)  (0) 2022.10.09
[Baekjoon] 앱(python)  (1) 2022.10.05
[Baekjoon] 미네랄(python)  (0) 2022.10.02