728x90
반응형
https://www.acmicpc.net/problem/1981
1981번: 배열에서 이동
n×n짜리의 배열이 하나 있다. 이 배열의 (1, 1)에서 (n, n)까지 이동하려고 한다. 이동할 때는 상, 하, 좌, 우의 네 인접한 칸으로만 이동할 수 있다. 이와 같이 이동하다 보면, 배열에서 몇 개의 수를
www.acmicpc.net
문제 해결
- (1,1)에서 (n,n)까지 가는데 거쳐간 수들 중 최솟값과 최댓값 차이를 구하는 문제
- 이동하면서 최솟값과 최댓값을 변경해가며 저장하고 갈 수도 있을 것 같은데 그러면 que안에 너무 많은 데이터가 저장이 되어 메모리 제한에 걸린다.
- 따라서 최솟값과 최댓값을 고정값으로 가져가며 그 안에 수들이 통과하여 이동할 수 있는지 확인해가는 식으로 bfs를 이용할 수 있다는 새로운 문제해결방식을 가져간다.(즉 이분탐색+BFS)
- 최솟값의 최솟값은 모든 행들(모든 열도 상관x)을 확인해가며 가장 작은 값을 찾으면 된다.
- 최솟값의 최댓값은 꼭 자니야하는 (1,1)과 (n,n)값 중 작은 값을 의미한다.
- 최댓값의 최솟값은 꼭 지나야하는 (1,1)과 (n,n)값 중 큰 값을 의미한다.
- 최댓값의 최댓값은 모든 행들을 확인해가며 가장 큰 값을 찾으면 된다.
- 그 후 최솟값을 최솟값의 최솟값에서 시작하고 최댓값을 최댓값의 최솟값에서 시작한다.
- 그렇게 (1,1)에서 (n,n)을 이동하는 bfs를 통과했을 때 answer = min(answer, right(최댓값)-left(최솟값))이 될 수 있다.
- 그러면 더 작은 값이 정답이 될 수 있는지 확인하기 위해 left += 1을 한다.
- 만약 bfs로 (1,1)에서 (n,n)을 이동하지 못한다면 최댓값 right +=1을 하여 통과할 수 있는지 확인한다.
- 만약 기존에 bfs를 한 번이상 통과하고 한 번이상 통과하지 못했다면 다음번 통과하지 못할 땐 left+=1, right+=1씩 한다. 왜냐하면 시간단축을 위해서인데 우리의 목적은 right-left의 최솟값이기 때문이다. 즉 left를 최대한 높여서 최솟값을 구해야하는데 bfs를 통과한 다음 다시 돌렸을 때 통과하지 못해 right+=1을 한다면, 다음번 돌렸을 때 bfs를 돌려서 통과를 하면 left+=1이 되는데 기존과 같은 값이 되기 때문에 의미가 없다는 것이다. (즉 left=1, right=3에서 통과해서 left=2가 되었을 때 통과를 못해서 left=2, right=4가 되었는데 이 때 통과를 해도 answer=2로 변함이 없다는 것이다. 이 경우 의미가 없다는 것이다. 우리는 answer<2인 경우가 있나 찾는 것이기 때문
CODE
import sys
input = sys.stdin.readline
from collections import deque
def bfs():
dxs = [1,-1,0,0]
dys = [0,0,1,-1]
que = deque()
visited = [[0]*n for _ in range(n)]
que.append((0,0))
visited[0][0] = 1
while que:
x, y = que.popleft()
if x==n-1 and y ==n-1:return 1
for dx, dy in zip(dxs, dys):
nx = x + dx
ny = y + dy
if 0<=nx<n and 0<=ny<n:
if left <= A[nx][ny] <= right and not visited[nx][ny]:
visited[nx][ny] = 1
que.append((nx,ny))
return 0
if __name__=='__main__':
n = int(input())
A = []
# 목적지까지 되착할 수 있는 범위의 최소범위의 범위와 최대범위의 범위를 구한다.
r_max = 0 # 가능한 최댓값의 최댓값
l_min = sys.maxsize # 가능한 최솟값의 최솟값
for _ in range(n):
row = list(map(int, input().split()))
A.append(row)
l_min = min(l_min, min(row)) # 모든 행중의 하나는 지나가야하므로
r_max = max(r_max, max(row))
l_max = min(A[0][0], A[n-1][n-1]) # 두 점은 반드시 지나므로 지나가는 점 중 두 점 중 작은 값이 나올 수 있는 가장 큰 최솟값이다.
r_min = max(A[0][0], A[n-1][n-1]) # 두 점은 반드시 지나므로 지나가는 점 중 두 점 중 큰 값이 나올 수 있는 가장 작은 최댓값이다.
left, right = l_min, r_min
answer = sys.maxsize
while l_min<=left <= l_max and r_min<=right<=r_max:
l_flag, r_flag = 0, 0
if bfs():
answer = min(answer, right-left)
left += 1
l_flag = 1
else:
if l_flag and r_flag:
left += 1
right +=1
else:
right += 1
r_flag = 1
print(answer)
728x90
반응형
'알고리즘 > [python] 백준 BOJ' 카테고리의 다른 글
[python] 백준 13335 트럭 (0) | 2023.12.10 |
---|---|
[python] 백준 1069 집으로 (2) | 2023.12.07 |
[python] 백준 30823 건공문자열 (3) | 2023.12.03 |
[python] 백준 2234 성곽 (2) | 2023.12.03 |
[python] 백준 1358 하키 (0) | 2023.11.30 |
댓글