본문 바로가기
코딩테스트/백준 알고리즘

백준 알고리즘 | 1697 : 숨바꼭질 (Python / 파이썬)

by 함께 공부해요 2020. 9. 27.


숨바꼭질 성공출처다국어분류

시간 제한

메모리 제한

제출

정답

맞은 사람

정답 비율

2 초

128 MB

86646

23923

14882

24.805%

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

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 ��

www.acmicpc.net


문제

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

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

입력

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

출력

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

힌트

수빈이가 5-10-9-18-17 순으로 가면 4초만에 동생을 찾을 수 있다.

알고리즘 분류

그래프 이론

그래프 탐색

너비 우선 탐색


 

백준 알고리즘 # 1697번 : 숨바꼭질

from collections import deque

def bfs():
    q = deque()             # deque는 양쪽에서 입출력 가능
    q.append(n)             # q = deque([5])
    while  q:
        x = q.popleft()     # 처음 시작점은 x = 5, q = deque([])
        if x == k:
            print(dist[x])
            break
        for nx in (x - 1, x + 1, x * 2):    # nx = 4, 6, 10
            if 0 <= nx <= MAX and not dist[nx]:
                dist[nx] = dist[x] + 1
                q.append(nx)    # q = deque([4, 6, "10"])

MAX = 10 ** 5               # 시간초과 안나게 수 제한
dist = [0] * (MAX + 1)      # 이동하는 거리를 알기 위한 변수
n, k = map(int, input().split())

bfs()

풀이

전에 공부했던 BFS(Breadth-first Search) 방법으로 문제를 풀 수 있어요.

먼저 bfs() 함수를 def로 정의하기 전에 MAX 변수를 설정해서 수를 제한하고

dist 변수를 설정해서 MAX에 1을 더한 수만큼 [0, 0, 0, ... , 0] 리스트를 만들었어요.

그리고 정수를 입력받을 n, k 변수를 설정하면 준비 끝🙌

+ 참고로 bfs()는 def로 정의한 bfs함수를 실행시키는 거에요! () ← 요녀석이 실행 버튼입니다.

다음으로 bfs() 함수 코드를 살펴보기 전에 python에 내장되어있는 collections에서 deque를 import(수입)해왔어요. deque는 정보처리기사를 준비하면서 공부했던 개념인데요.

'''

key point 1

선형 구조로서의 자료구조로는 크게 Stack, Queue, Deque가 있는데 StackLIFO(Last In First Out) 특성으로 가장 먼저 넣은 것이 맨 아래에 있기 때문에 가장 마지막에 나오고, 가장 마지막에 넣은 것이 맨 위에 있기 때문에 가장 먼저 나와요.

Queue의 특성은 FIFO(First In First Out)으로 가장 먼저 넣은 것이 쭉 큐를 통과해서 가장 먼저 나오게 되요. 그리고 Deque가 있는데, Queue와 Deque의 가장 큰 차이점은 Queue는 한 쪽에는 입력만 하고 반대쪽은 출력만 하는 반면, Deque는 양쪽 모두 입출력이 가능해요.

'''

자 그럼 이렇게 Deque의 특성까지 알아봤으니 bfs() 함수 코드를 자세히 풀이하면

q 변수를 deque()로 초기화하고 q.append(n)을 통해서

q = deque([5])

위와 같이 시작점을 deque에 추가해줬어요.

그리고 while 반복문을 사용해서 q가 정수일 때 계속해서 반복하게 하고

'''

key point 2

x 변수를 설정해서 deque에 들어있는 수를 left로 pop, 빼주었어요.

즉, leftpop()은 deque() 왼쪽에 있는 수를 빼주는 함수에요.

'''

다음으로 if문을 사용해서 x 변수인 수빈이의 위치가 동생이 있는 k와 같아진다면

얼마의 시간이 걸렸는지 print()하고 break로 while문을 멈춰요.

'''

key point 3

이제 가장 중요한 for문인데요.

for nx in (x - 1, x + 1, x * 2)에 x = 5를 대입시키면, nx = 4, 6, 10 이라는 값을 갖게 되요.

이것을 들여쓰기된 if문에서 0 <= 4, 6, 10 <= MAX 와(and)

(if) not dist[4, 6, 10], 즉 if문의 조건인 dist[4, 6, 10]이 거짓일 경우

제가 위의 not dist를 강조한 이유는 dist 변수로 설정한 것은 [0, 0, 0, ..., 0, 0]과 같이

0을 가지고 있는 리스트이기 때문에 dist[nx]의 값은 처음에는 무조건 0이 나올 수 밖에 없는데요.

이것을 다시 생각하면 dist[nx]는 0, 즉 언제나 False라는 점이에요!

때문에 if not dist[nx]는 조건이 언제나 거짓인 False이니 if문을 만족시키는 것이죠.

(이 부분이 이해가 잘 안가서 골똘히 머리 굴려봤습니다 ㅋㅋㅋㅋ)

반대로 if dist[nx]: 이렇게 되있었다면 dist[nx]는 0의 값인 False이니 if문의 조건이 거짓이어서

if문이 돌아가지 않겠죠??

'''

자 이렇게 if문까지 통과했으면 다 끝났어요..!!

dist[4, 6, 10] = dist[5] + 1 = 0 + 1 = 1

이렇게 dist[nx]의 값은 dist[x]에서 1씩을 더해주게 되는데요.

즉 dist[4, 6, 10]의 값 모두 1을 갖게 되고, deque에 들어가게 되는거에요.

q = deque([4, 6, 10])

이것을 그림으로 보면

출처:  https://deepwelloper.tistory.com/75

위와 같이 하나하나씩 쭉 따라가는 것을 알 수 있어요.

여기서 힌트에 주어진 "수빈이가 5-10-9-18-17 순으로 가면 4초만에 동생을 찾을 수 있다."를 따라가보면

dist[10]을 하면 되겠죠? (x = 10, 즉 10을 popleft 한 값)

그럼 다시 nx = 9, 11, 20의 값을 갖게되고, dist[9, 11, 20] = dist[10] + 1 = 1 + 1 = 2

이처럼 9, 11, 20은 다시 2의 값을 갖고 deque에 들어가 q = deque([9, 11, 20])이 되고

다시 popleft()로 x = 9를 꺼내서 nx = 8, 10, 18 중 18을 사용하게 되면

dist[18] = dist[9] + 1 = 2 + 1 = 3

위와 같아지죠!! 마지막으로!!! q = deque([18])을 popleft()로 빼서 x = 18을 for문으로 돌려주면!!!

nx = 17, 19, 36

드디어 nx에 17이 보였네요! 마지막으로 for문을 돌려주고

dist[17, 19, 36] = dist[18] + 1 = 3 + 1 = 4이므로

q = deque([17, 19, 36])에 있는 q 중에서

x = q.popleft()를 하면 x는 17의 값을 갖게 되고 q = deque([19, 36])만 남게되요.

마지막으로 if문 x == k에 의해서 dist[17]의 값인 4가 출력되면서 풀이 끄---읏!!!👏

세한 코드가 궁금하신 분들은 아래 GitHub 코드를 참고해주세요🙏

 

wook2124/Algorithm-Test

Practice algorithm. Contribute to wook2124/Algorithm-Test development by creating an account on GitHub.

github.com

최종 소스코드

댓글