장 준
씨포유
장 준
전체 방문자
오늘
어제
  • 분류 전체보기 (91)
    • 프로그래밍언어 (15)
      • c언어 (10)
      • 파이썬 (0)
      • 자바스크립트 (5)
    • PS (58)
      • 알고리즘 이론 (18)
      • 프로그래머스 (5)
      • 백준 (35)
    • CS (16)
      • 자료구조 (5)
      • 운영체제 (3)
      • 네트워크 (5)
      • 데이터베이스 (0)
      • 기초 지식 (3)
    • 브랜드 (1)

블로그 메뉴

  • 태그

인기 글

태그

  • CS
  • Implementation
  • DFS
  • 기초 지식
  • python3
  • C
  • 자바스크립트
  • JS
  • BFS
  • Visual Studio
  • 알고리즘
  • 프로그래밍언어
  • 씨포유
  • PS
  • nodejs
  • Network
  • 파이썬
  • 프로그래머스
  • Kruskal algorithm
  • Stack
  • 백준
  • 코딩테스트
  • pypy3
  • recursion
  • Priority Queue
  • DP
  • codesandbox
  • JavaScript
  • bitmask
  • 자료구조

최근 댓글

최근 글

hELLO · Designed By 정상우.
장 준

씨포유

[백준(BOJ)] #1194- 달이 차오른다, 가자. (파이썬, PyPy3)
PS/백준

[백준(BOJ)] #1194- 달이 차오른다, 가자. (파이썬, PyPy3)

2022. 10. 30. 21:49
728x90

문제

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

 

1194번: 달이 차오른다, 가자.

첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고,

www.acmicpc.net

 


문제 풀이

BFS와 비트마스크 활용

 

2022.07.14 - [PS/알고리즘 이론] - [파이썬으로 배우는 알고리즘] BFS(너비 우선 탐색)

 

[파이썬으로 배우는 알고리즘] BFS(너비 우선 탐색)

BFS란? BFS(Breadth First Search)는 DFS와 마찬가지로 그래프의 모든 노드를 탐색하는 방법 중 하나로, 너비를 우선으로 탐색한 후 인접한 노드부터 탐색하는 알고리즘입니다. 스택 자료구조를 활용하는

c4u-rdav.tistory.com

2022.07.15 - [PS/알고리즘 이론] - [파이썬으로 배우는 알고리즘] 비트마스크(BitMask)

 

[파이썬으로 배우는 알고리즘] 비트마스크(BitMask)

비트마스크(BitMask)란? 컴퓨터는 내부적으로 모든 데이터를 이진수로 표현을 합니다. 예전에 c언어로 비트 체계와 비트 연산자를 간단히 다룬 적이 있는데 비트에 대해서 궁금하신 분들은 참고하

c4u-rdav.tistory.com

 

열쇠 획득

a, b, c, d, e, f 총 여섯 개의 열쇠를 비트로 나타냅니다.

열쇠 비트 십진수
a 0 0 0 0 0 1 1
b 0 0 0 0 1 0 2
c 0 0 0 1 0 0 4
d 0 0 1 0 0 0 8
e 0 1 0 0 0 0 16
f 1 0 0 0 0 0 32

 

열쇠를 아무것도 가지고 있지 않은 상태를 0(이진수 000000)으로 가정해봅시다.

현재 상태 비트 십진수
아무 열쇠도 없음 0 0 0 0 0 0 0

 

미로를 탐색하다가 b라는 열쇠를 발견합니다. 열쇠 b는 2(이진수 000010)로 원래 상태와 열쇠 b를 OR 연산을 하여 열쇠 b를 획득한 상태를 유지하게 됩니다. 000000 | 000010 = 000010(십진수 2)

현재 상태 비트 십진수
b 열쇠 소지 0 0 0 0 1 0 2

 

이어서 미로를 탐색하다가 f라는 열쇠를 발견합니다. 열쇠 f는 2(이진수 100000)로 원래 상태와 열쇠 f를 OR 연산을 하여 열쇠 f를 획득한 상태를 유지하게 됩니다. 100000 | 000010 = 100010(십진수 34)

현재 상태 비트 십진수
b, f 열쇠 소지 1 0 0 0 1 0 34

 

이렇게 획득할 수 있는 열쇠는 a, b, c, d, e, f로 표현할 수 있는 수는 최대 63(이진수 111111)입니다.

현재 상태 비트 십진수
a, b, c, d, e, f 열쇠 소지 1 1 1 1 1 1 63

 

문 열기

미로에서 특정 문에 도착했을 때는 AND 연산으로 문을 열 수 있는지 없는지 확인할 수 있습니다.

문도 열쇠와 마찬가지로 각 알파벳에 맞춰 비트로 나타냅니다.

문 비트 십진수
A 0 0 0 0 0 1 1
B 0 0 0 0 1 0 2
C 0 0 0 1 0 0 4
D 0 0 1 0 0 0 8
E 0 1 0 0 0 0 16
F 1 0 0 0 0 0 32

 

a, b, c 열쇠를 소지하고 있는 상태에서 문 B에 도착합니다.

현재 상태 비트 십진수
a, b, c 열쇠 소지 0 0 0 1 1 1 7

문 B는 000010이고 현재 상태는 000111입니다. 이제 이 둘을 AND 연산시킵니다. AND 연산하여 얻을 수 있는 값은 000010 & 000111 = 000010(십진수 2)이고 0이 아니므로 문을 열 수 있게 됩니다.

 

이번엔 a, b, c 열쇠를 소지하고 있는 상태에서 문 F에 도착합니다.

문 F는 100000이고 현재 상태는 000111입니다. 이제 이 둘을 AND 연산시킵니다. AND 연산하여 얻을 수 있는 값은 100000 & 000111 = 000000(십진수 0)이고 0이므로 문을 열 수 없습니다.

 

BFS

열쇠를 갖고 있는 상태는 0~63으로 크기가 64입니다. 이 상태를 S로 두고 N x M x S인 3차원 리스트를 사용해 미로를 탐색하며 열쇠 상태에 따른 이동 횟수를 구하면 됩니다.

 


구현

코드

import sys
from collections import deque
input = sys.stdin.readline

if __name__ == "__main__":
    N, M = map(int, input().split())
    board = [list(input().rstrip()) for _ in range(N)]

	# 시작 좌표구하기
    def get_start_point():
        for i in range(N):
            for j in range(M):
                if board[i][j] == '0':
                    return i, j

    def bfs(p):
        dx = [-1, 0, 1, 0]
        dy = [0, 1, 0, -1]

        visited = [[[0] * 64 for _ in range(M)] for _ in range(N)]
        dq = deque()
        total_cnt = -1
        x, y = p
        dq.append((x, y, 0))
        visited[x][y][0] = 1

        while dq:
            tx, ty, tz = dq.popleft()
            if board[tx][ty] == '1':
                total_cnt = visited[tx][ty][tz] - 1
                break
            for k in range(4):
                x = tx + dx[k]
                y = ty + dy[k]
                # 범위를 벗어났거나 방문했거나 벽일 경우
                if not (0 <= x < N and 0 <= y < M and visited[x][y][tz] == 0 and board[x][y] != '#'):
                    continue
                # 열쇠인 경우
                if board[x][y] in ['a', 'b', 'c', 'd', 'e', 'f']:
                    z = tz | (1 << (ord(board[x][y]) - ord('a')))
                    if visited[x][y][z] == 0:
                        visited[x][y][z] = visited[tx][ty][tz] + 1
                        dq.append((x, y, z))
                # 문인 경우
                elif board[x][y] in ['A', 'B', 'C', 'D', 'E', 'F']:
                    if tz & (1 << (ord(board[x][y]) - ord('A'))):
                        visited[x][y][tz] = visited[tx][ty][tz] + 1
                        dq.append((x, y, tz))
                # 길인 경우
                else:
                    visited[x][y][tz] = visited[tx][ty][tz] + 1
                    dq.append((x, y, tz))
        return total_cnt

    p = get_start_point()
    print(bfs(p))

 

결과

728x90
반응형
저작자표시 (새창열림)

'PS > 백준' 카테고리의 다른 글

[백준(BOJ)] #1525- 퍼즐 (파이썬, PyPy3)  (0) 2022.11.03
[백준(BOJ)] #1103- 게임 (파이썬, PyPy3)  (0) 2022.11.02
[백준(BOJ)] #1655- 가운데를 말해요 (파이썬, PyPy3)  (0) 2022.10.20
[백준(BOJ)] #1300- K번째 수 (파이썬, PyPy3)  (0) 2022.10.19
[백준(BOJ)] #2436- 공약수 (파이썬, PyPy3)  (0) 2022.10.14
    'PS/백준' 카테고리의 다른 글
    • [백준(BOJ)] #1525- 퍼즐 (파이썬, PyPy3)
    • [백준(BOJ)] #1103- 게임 (파이썬, PyPy3)
    • [백준(BOJ)] #1655- 가운데를 말해요 (파이썬, PyPy3)
    • [백준(BOJ)] #1300- K번째 수 (파이썬, PyPy3)
    장 준
    장 준
    C4U(Computer For You)

    티스토리툴바