λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸƒ algorithm/programmers

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ Level 3 - 블둝 μ΄λ™ν•˜κΈ°

by HandHand 2021. 3. 1.

문제

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ - 블둝 μ΄λ™ν•˜κΈ°

풀이 κ³Όμ •

λ‘œλ΄‡μ΄ 이동할 수 μžˆλŠ” λͺ¨λ“  경우λ₯Ό 따져보며 탐색을 μˆ˜ν–‰ν•˜λ©΄ λœλ‹€.

μ΅œλ‹¨ 경둜λ₯Ό 찾으면 λ°”λ‘œ 탐색을 μ’…λ£Œν•˜λ©΄λ˜λ―€λ‘œ 같은 depth의 μƒνƒœλ“€μ„ νƒμƒ‰ν•˜κΈ° μœ„ν•΄ BFSλ₯Ό μ‚¬μš©ν–ˆλ‹€.

λ‹€λ§Œ λ‘œλ΄‡μ˜ μƒνƒœμ™€ νšŒμ „ 연산을 κ΅¬ν˜„ν•˜λŠ” 뢀뢄이 맀우 κΉŒλ‹€λ‘œμ› λ‹€..

λ‘œλ΄‡μ˜ μƒνƒœ λ‚˜νƒ€λ‚΄κΈ°

μ²˜μŒμ—λŠ” board에 λ‘œλ΄‡μ˜ μƒνƒœλ₯Ό ν‘œμ‹œν•΄μ£Όλ©° 이λ₯Ό 탐색에 ν™œμš©ν•˜μ˜€μ§€λ§Œ μ–Όλ§ˆ μ§€λ‚˜μ§€ μ•Šμ•„ 이 방법이 ꡉμž₯히 λΉ„νš¨μœ¨μ μ΄λΌλŠ” 것을 μ•Œκ²Œ λ˜μ—ˆλ‹€.

μ–΄μ°¨ν”Ό boardλŠ” 고정이고 μš°λ¦¬λŠ” λ‘œλ΄‡μ˜ μœ„μΉ˜λ§Œ λ³€κ²½μ‹œν‚€λ©΄μ„œ 탐색을 μˆ˜ν–‰ν•˜λ©΄ λ˜λ―€λ‘œ board λŒ€μ‹  λ‘œλ΄‡μ˜ μ£„ν‘œκ°’μ„ 톡해 탐색을 μˆ˜ν–‰ν•˜λ„λ‘ ν•˜μ˜€λ‹€.

문제 풀이 ν›„ λ‹€λ₯Έ μ‚¬λžŒλ“€μ˜ μ½”λ“œλ„ λ΄€λŠ”λ° visited 배열을 λ”°λ‘œ μœ μ§€ν•˜κ³  Queue에 κ±Έλ¦° μ‹œκ°„μ„ μ’Œν‘œκ°’κ³Ό ν•¨κ»˜ λ„£μ–΄μ€€ 것이 μΈμƒμ μ΄μ—ˆλ‹€.
μ΄λ ‡κ²Œ ν•˜λ©΄ hashable 객체둜 λ°”κΏ”μ„œ λ”•μ…”λ„ˆλ¦¬μ— λ„£μœΌλ €κ³  ꡳ이 listλ₯Ό tuple둜 λ³€κ²½ν•˜μ§€ μ•Šμ•„λ„ 될 것 κ°™λ‹€.

λ‘œλ΄‡ νšŒμ „μ‹œν‚€κΈ°

이번 λ¬Έμ œμ—μ„œ κ°€μž₯ κΉŒλ‹€λ‘œμ› λ˜ νšŒμ „ 연산을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„œλŠ” 상,ν•˜,쒌,우 이동과 4κ°€μ§€μ˜ νšŒμ „ 연산을 λͺ¨λ‘ μ²΄ν¬ν•΄μ€˜μ•Όν•œλ‹€.

μƒν•˜μ’Œμš° μ’Œν‘œκ°’λ“€μ„ κ²€μ‚¬ν•˜λŠ”κ±΄ λ‹€λ₯Έ λ¬Έμ œλ“€κ³Ό λ‹€λ₯Έ 것이 μ—†μ§€λ§Œ νšŒμ „ 연산이 κ°€λŠ₯ν•œμ§€λŠ” μ–΄λ–»κ²Œ μ•Œ 수 μžˆμ„κΉŒ?

생각해보면 νšŒμ „ 연산을 μœ„ν•΄μ„œλŠ” νšŒμ „ν•˜κ³  싢은 λ°©ν–₯이 무쑰건 λͺ¨λ‘ λΉ„μ–΄μžˆλŠ” μƒνƒœμ—¬μ•Ό ν•œλ‹€λŠ” 것을 μ•Œ 수 μžˆλ‹€.

μ•„λž˜μ™€ 같이 ν•œκ΅°λ°λΌλ„ 벽이 μžˆλ‹€λ©΄ κ·Έ μͺ½μœΌλ‘œλŠ” νšŒμ „μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.

λ”°λΌμ„œ λ‚˜λŠ” 이전에 상,ν•˜,쒌,우 μ€‘μ—μ„œ 이동이 κ°€λŠ₯ν–ˆλ˜ 연산듀을 μ €μž₯해놓은 λ‹€μŒ, 그에 λ§žλŠ” νšŒμ „ μ£„ν‘œκ°’λ“€μ„ 생성해쀬닀.

μ΄λ•Œ μ£Όμ˜ν•  점은 λ‚˜μ˜ κ΅¬ν˜„ 방식을 κΈ°μ€€μœΌλ‘œ νšŒμ „λœ μ’Œν‘œκ°’μ€ λ‘œλ΄‡μ˜ 두 μ’Œν‘œ 쀑 항상 μ™Όμͺ½ or μƒλ‹¨μ˜ μ’Œν‘œκ°€ λ¨Όμ € λ‚˜μ˜€λ„λ‘ μƒμ„±ν•΄μ€˜μ•Ό ν•œλ‹€λŠ” 것이닀.
이거 λ•Œλ¬Έμ— μ²˜μŒμ— 계속 μ‹€νŒ¨ν–ˆμ—ˆλ‹€..

μ½”λ“œ


from collections import deque


dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]


def move(board, here):
    N = len(board)
    movable = []
    movable_dir = []  # 이동 κ°€λŠ₯ν•œ λ°©ν–₯
    # μƒν•˜μ’Œμš°
    for i in range(4):
        next = [0, 0, 0, 0]
        next[0] = here[0] + dx[i]
        next[1] = here[1] + dy[i]
        next[2] = here[2] + dx[i]
        next[3] = here[3] + dy[i]

        if next[0] < 0 or next[0] >= N or next[1] < 0 or next[1] >= N:
            continue
        if next[2] < 0 or next[2] >= N or next[3] < 0 or next[3] >= N:
            continue
        if board[next[0]][next[1]] == 1 or board[next[2]][next[3]] == 1:
            continue
        movable.append(tuple(next))
        movable_dir.append(i)
    # νšŒμ „
    axis1 = here[:2]
    axis2 = here[2:]

    # κ°€λ‘œλ‘œ λ†“μ—¬μžˆμ„ 경우
    if axis1[0] == axis2[0]:
        # μ•„λž˜κ°€ λ‹€ λΉ„μ–΄μ„œ 이동 κ°€λŠ₯ν•  경우
        if 2 in movable_dir:
            there1 = axis1 + (axis2[0] + 1, axis2[1] - 1)
            there2 = axis2 + (axis1[0] + 1, axis1[1] + 1)
            movable.append(there1)
            movable.append(there2)
        # μœ„μ—κ°€ λ‹€ λΉ„μ–΄μ„œ 이동 κ°€λŠ₯ν•  경우
        if 3 in movable_dir:
            there1 = (axis2[0] - 1, axis2[1] - 1) + axis1
            there2 = (axis1[0] - 1, axis1[1] + 1) + axis2
            movable.append(there1)
            movable.append(there2)
    # μ„Έλ‘œλ‘œ λ†“μ—¬μžˆμ„ 경우
    else:
        # 였λ₯Έμͺ½μ΄ λ‹€ λΉ„μ–΄μ„œ 이동 κ°€λŠ₯ν•  경우
        if 0 in movable_dir:
            there1 = axis1 + (axis2[0] - 1, axis2[1] + 1)
            there2 = axis2 + (axis1[0] + 1, axis1[1] + 1)
            movable.append(there1)
            movable.append(there2)
        # μ™Όμͺ½μ΄ λ‹€ λΉ„μ–΄μ„œ 이동 κ°€λŠ₯ν•  경우
        if 1 in movable_dir:
            there1 = (axis2[0] - 1, axis2[1] - 1) + axis1
            there2 = (axis1[0] + 1, axis1[1] - 1) + axis2
            movable.append(there1)
            movable.append(there2)

    return movable


def solution(board):
    # 처음 λ‘œλ΄‡ μœ„μΉ˜
    start = (0, 0, 0, 1)

    N = len(board)
    cost = {}  # κ±Έλ¦° μ‹œκ°„
    q = deque()

    cost[start] = 0
    q.append(start)

    while True:
        here = q[0]
        q.popleft()
        if here[0] == N-1 and here[1] == N-1 or here[2] == N-1 and here[3] == N-1:
            answer = cost[here]
            break

        move_list = move(board, here)
        for there in move_list:
            if there not in cost:
                cost[there] = cost[here] + 1
                q.append(there)

    return answer


board = [[0, 0, 0, 0, 0],[1, 1, 1, 0, 0],[1, 1, 1, 1, 0],[1, 1, 1, 1, 0],[1, 1, 1, 0, 0]]
print(solution(board))  # κ²°κ³ΌλŠ” 7
λ°˜μ‘ν˜•

πŸ’¬ λŒ“κΈ€