728x90

백준 파이썬 공부 2024.12.07
1697번 숨바꼭질 (실버 1)

1. 문제
수빈이는 동생과 숨바꼭질을 하고 있다. 
수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 
수빈이는 걷거나 순간이동을 할 수 있다. 
만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 
순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.

수빈이와 동생의 위치가 주어졌을 때, 
수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.

2. 입력
첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. 
N과 K는 정수이다.

3. 출력
수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.

4. 문제 해설
경로의 길이가 같다는 가정 하에 최소 경로를 찾는 문제

이동의 방식은 3가지 (소요시간은 1초로 동일)
(1) +1 (2) -1 (3) *2

이 말은 n 이하의 위치로는 -1로 밖에 이동하지 못하며,
n 이상의 위치로는 세가지 방법 중 최단 거리 선택하여 이동한다.

일단 최소 경로를 찾는 방법은 DP(다이나믹 프로그래밍)을 사용하는 것이 좋을 것으로 보인다.

>>코드 1. DP 사용 시도 >> 오류 발생

n, k = map(int, input().split())
road = [0 for i in range(100001)]

for i in range(1, n):
    road[i] = n-i
for i in range(n+1, k+1):
    if i%2 == 0:
        road[i] = min(road[i//2] + 1, road[i-1] + 1)
    else:
        road[i] = min(road[i//2] + 2, road[i-1] + 1)
print(road[k])



아... 이게 역방향(-1)로도 이동하는 것이 가능하다 보니,
순서대로 이전 인덱스의 최단거리값들 만으로는 정확한 최단거리 탐색이 불가능하다.

그렇다면, BFS 너비 우선 탐색을 이용홰보자.
너비우선 탐색이라는 것이 결국은 최단거리를 찾는 방식이라고 볼 수 있다.

- 덱을 선언하고, BFS 탐색을 시행한다.
- 해당 노드와 연결된 다음 노드는 3가지 (+1, -1, *2)
- 다음 노드가 0 이상, 100000 이하 면서, 방문한 적 없는 노드 일때
- 이동거리 계산(visited[next_node] = visited[node] + 1) 및 덱에 추가(queue.append(next_node))
- popleft 한 노드(현재 노드)가 k와 같은 경우 return visited[node]

5. 정답 코드

from collections import deque

def BFS(start, end):
    visited = [-1 for i in range(100001)]
    visited[start] = 0
    
    queue = deque()
    queue.append(start)
    
    while queue:
        node = queue.popleft()
        if node == end:
            return visited[end]
        for next_node in [node-1, node+1, node*2]:
            if 0 <= next_node <= 100000 and visited[next_node] == -1:
                visited[next_node] = visited[node] + 1
                queue.append(next_node)

n, k = map(int, input().split())
print(BFS(n, k))



6. 문제링크
https://www.acmicpc.net/problem/1697

728x90

+ Recent posts