[ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค] ํผ์ฆ์กฐ๊ฐ ์ฑ„์šฐ๊ธฐ (Python, BFS, ๊ตฌํ˜„)

๋ฐ˜์‘ํ˜•

๐ŸŒฑ ๋ฌธ์ œ

BFS/DFS ๋ฌธ์ œ์ด์ง€๋งŒ ๊ฐœ์ธ์ ์œผ๋กœ BFS ์ฐ”๋” ์“ฐ๊ณ , ์™„์ „ ๋นก์Žˆ ๊ตฌํ˜„์ธ ๊ฒƒ ๊ฐ™์•˜๋˜.. ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

 

ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค

์ฝ”๋“œ ์ค‘์‹ฌ์˜ ๊ฐœ๋ฐœ์ž ์ฑ„์šฉ. ์Šคํƒ ๊ธฐ๋ฐ˜์˜ ํฌ์ง€์…˜ ๋งค์นญ. ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค์˜ ๊ฐœ๋ฐœ์ž ๋งž์ถคํ˜• ํ”„๋กœํ•„์„ ๋“ฑ๋กํ•˜๊ณ , ๋‚˜์™€ ๊ธฐ์ˆ  ๊ถํ•ฉ์ด ์ž˜ ๋งž๋Š” ๊ธฐ์—…๋“ค์„ ๋งค์นญ ๋ฐ›์œผ์„ธ์š”.

programmers.co.kr

 

 

 

๐ŸŒฑ ํ’€์ด

1. game_board์˜ ๋นˆ ๊ณต๊ฐ„๊ณผ table์˜ ํผ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅ

์šฐ์„ , game_board์—์„œ ๋นˆ๊ณต๊ฐ„๊ณผ table์—์„œ ํผ์ฆ๋“ค์˜ ์ •๋ณด๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, game_board์—์„œ๋Š” 0์˜ ์œ„์น˜, table์—์„œ๋Š” 1์˜ ์œ„์น˜๋ฅผ ์•Œ์•„์•ผํ•ฉ๋‹ˆ๋‹ค. game_board์˜ ์ธ์ ‘ํ•œ 0๋“ค์€ ํ•˜๋‚˜์˜ ํผ์ฆ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ํ•˜๋‚˜์˜ ๋นˆ๊ณต๊ฐ„์œผ๋กœ ์ทจ๊ธ‰ํ•˜๊ณ , table์—์„œ ์ธ์ ‘ํ•œ 1์€ ํ•˜๋‚˜์˜ ํผ์ฆ์ด๋ฏ€๋กœ BFS ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐ™์€ BFS ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ game_board์™€ table๋กœ ๋‘ ๋ฒˆ ์จ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ํ™” ํ•˜์˜€๊ณ , ์ด๋•Œ game_board์—์„œ๋Š” 0์˜ ์œ„์น˜๋ฅผ table์—์„œ๋Š” 1์˜ ์œ„์น˜๋ฅผ ์•Œ์•„์•ผ ํ•˜๋ฏ€๋กœ find_block() ํ•จ์ˆ˜์—์„œ f ์ธ์ž๋ฅผ ๋ฐ›์•„ XOR(^) ์—ฐ์‚ฌ์ž์™€ ํ•จ๊ป˜ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ 0์™€ 1๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์•Œ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.


  
from collections import deque
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
def find_block(board, f):
empty_board_list = []
visited = [[False] * len(board[0]) for _ in range(len(board))]
for i in range(len(board)):
for j in range(len(board[i])):
if not visited[i][j] and board[i][j] == f:
queue = deque([(i, j)])
board[i][j] = f ^ 1
visited[i][j] = True
lst = [(i, j)]
while queue:
x, y = queue.popleft()
for _ in range(4):
nx, ny = x + dx[_], y + dy[_]
if nx < 0 or nx > len(board) - 1 or ny < 0 or ny > len(board) - 1:
continue
elif board[nx][ny] == f:
queue.append((nx, ny))
board[nx][ny] = f ^ 1
visited[nx][ny] = True
lst.append((nx, ny))
empty_board_list.append(lst)
return empty_board_list

 

์•„๋ž˜์˜ game_board์™€ table ์ •๋ณด๋ฅผ find_block() ํ•จ์ˆ˜์— ๋„ฃ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ธ”๋ก๋“ค์˜ ์ •๋ณด๊ฐ€ ๋‹ด๊น๋‹ˆ๋‹ค.


  
game_board = [
[1, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0],
[0, 1, 1, 0, 0, 1],
[1, 1, 0, 1, 1, 1],
[1, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 0, 0]
]
table = [
[1, 0, 0, 1, 1, 0],
[1, 0, 1, 0, 1, 0],
[0, 1, 1, 0, 1, 1],
[0, 0, 1, 0, 0, 0],
[1, 1, 0, 1, 1, 0],
[0, 1, 0, 0, 0, 0]
]
empty_blocks = find_block(game_board, 0)
# [[(0, 2), (0, 3), (1, 3), (2, 3), (2, 4)], [(0, 5), (1, 5)], [(1, 0), (1, 1), (2, 0)], [(3, 2), (4, 2), (4, 1), (4, 3)], [(4, 5), (5, 5), (5, 4)], [(5, 0)]]
puzzles = find_block(table, 1)
# [[(0, 0), (1, 0)], [(0, 3), (0, 4), (1, 4), (2, 4), (2, 5)], [(1, 2), (2, 2), (2, 1), (3, 2)], [(4, 0), (4, 1), (5, 1)], [(4, 3), (4, 4)]]

 

2. ์ธ๋ฑ์Šค ์ •๋ณด๋กœ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ

์ธ๋ฑ์Šค ์ •๋ณด๋กœ table ๋ชจ์–‘, ์ฆ‰ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๋งŒ๋“ค ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด ์•ž์„œ find_blocks() ํ•จ์ˆ˜์—์„œ ์ฐพ์€ [(0, 2), (0, 3), (1, 3), (2, 3), (2, 4)] ์ •๋ณด๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์€ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ €๋Š” make_table()๋ผ๋Š” ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๊ณ  ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.


  
def make_table(block):
x, y = zip(*block)
c, r = max(x) - min(x) + 1, max(y) - min(y) + 1
table = [[0] * r for _ in range(c)]
for i, j in block:
i, j = i - min(x), j - min(y)
table[i][j] = 1
return table

 

3. 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋ฅผ ํšŒ์ „ํ•˜๋Š” ํ•จ์ˆ˜

์ด ๋ฌธ์ œ์—์„œ ์ค‘์š”ํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ํผ์ฆ์€ 90๋„์”ฉ ํšŒ์ „ํ•˜๋ฉด์„œ ๋นˆ์นธ์„ ์ฑ„์šธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์—์„œ ๋งŒ๋“  ํผ์ฆ์˜ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋ฅผ 90๋„์”ฉ ํšŒ์ „ํ•ด๋ณด๋ฉด์„œ ๋นˆ์นธ๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ 90๋„์”ฉ ํšŒ์ „ํ•˜๋Š” rotate() ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ, ๋ฌธ์ œ์—์„œ ํผ์ฆ๋กœ ์ฑ„์šด ๋นˆ์นธ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฌผ์–ด๋ณด๊ธฐ ๋•Œ๋ฌธ์— rotateํ•จ์ˆ˜์—์„œ ํผ์ฆ์˜ ํฌ๊ธฐ, ์ฆ‰ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ์—์„œ 1์˜ ๊ฐœ์ˆ˜๋„ ํ•จ๊ป˜ ์นด์šดํŠธํ•˜์—ฌ ๋ฆฌํ„ดํ•ด์ค๋‹ˆ๋‹ค


  
def rotate(puzzle):
rotate = [[0] * len(puzzle) for _ in range(len(puzzle[0]))]
count = 0
for i in range(len(puzzle)):
for j in range(len(puzzle[i])):
if puzzle[i][j] == 1:
count += 1
rotate[j][len(puzzle) - 1 - i] = puzzle[i][j]
return rotate, count

 

์ด์ œ solution ํ•จ์ˆ˜์—์„œ ์œ„์—์„œ ์ ์ ˆํžˆ ๊ตฌํ˜„ํ•ด ๋†“์€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋‹ต์„ ๋ฆฌํ„ดํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. 


  
def solution(game_board, table):
answer = 0
empty_blocks = find_block(game_board, 0)
puzzles = find_block(table, 1)
for empty in empty_blocks:
filled = False
table = make_table(empty)
for puzzle_origin in puzzles:
if filled == True:
break
puzzle = make_table(puzzle_origin)
for i in range(4):
puzzle, count = rotate(puzzle)
if table == puzzle:
answer += count
puzzles.remove(puzzle_origin)
filled = True
break
  • empty_blocks, puzzles์— ๋นˆ๊ณต๊ฐ„๊ณผ ํผ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋นˆ๊ณต๊ฐ„์„ ํ•˜๋‚˜์”ฉ ๋Œ๋ฉด์„œ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค๊ณ (make_table()
  • ๋นˆ๊ณต๊ฐ„์— ๋Œ€ํ•ด์„œ puzzle๋“ค์„ ํ•˜๋‚˜์”ฉ ๋Œ๋ฉด์„œ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค๊ณ  4๋ฒˆ ํšŒ์ „ ์‹œํ‚ค๋ฉด์„œ ๋นˆ๊ณต๊ฐ„์˜ ๋ชจ์–‘๊ณผ ํผ์ฆ์˜ ๋ชจ์–‘์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. (๋‘ ๊ฐœ์˜ 2์ฐจ์› ๋ฆฌ์ŠคํŠธ(table(๋นˆ๊ณต๊ฐ„)์™€ puzzle(ํผ์ฆ))์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ)
  • filled ๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ๋นˆ๊ณต๊ฐ„์ด ์ด๋ฏธ ์ฑ„์›Œ์กŒ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ณ€์ˆ˜๋กœ, filled๊ฐ€ True์ด๋ฉด puzzle์„ ํ™•์ธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • puzzles.remove(puzzle_origin)์œผ๋กœ ํผ์ฆ์„ ๋นˆ๊ณต๊ฐ„์— ์ฑ„์› ์„ ๋•Œ puzzles์—์„œ ์ œ๊ฑฐํ•˜์—ฌ ๋‹ค์Œ ๋นˆ๊ณต๊ฐ„์—์„œ ์ค‘๋ณต๋˜์–ด ์ฑ„์›Œ์ง€์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

๐ŸŒฑ ์ •๋‹ต ์ฝ”๋“œ


  
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# programmers ํผ์ฆ์กฐ๊ฐ์ฑ„์šฐ๊ธฐ
from collections import deque
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
# board์™€ puzzle์˜ ๊ฐ๊ฐ ๋นˆ๊ณต๊ฐ„๊ณผ ๋ธ”๋Ÿญ์„ ์ฐพ๋Š” ํ•จ์ˆ˜ (BFS)
def find_block(board, f):
empty_board_list = []
visited = [[False] * len(board[0]) for _ in range(len(board))]
for i in range(len(board)):
for j in range(len(board[i])):
if not visited[i][j] and board[i][j] == f:
queue = deque([(i, j)])
board[i][j] = f ^ 1
visited[i][j] = True
lst = [(i, j)]
while queue:
x, y = queue.popleft()
for _ in range(4):
nx, ny = x + dx[_], y + dy[_]
if nx < 0 or nx > len(board) - 1 or ny < 0 or ny > len(board) - 1:
continue
elif board[nx][ny] == f:
queue.append((nx, ny))
board[nx][ny] = f ^ 1
visited[nx][ny] = True
lst.append((nx, ny))
empty_board_list.append(lst)
return empty_board_list
# block์˜ ์ธ๋ฑ์Šค๋“ค๋กœ table์„ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜
def make_table(block):
x, y = zip(*block)
c, r = max(x) - min(x) + 1, max(y) - min(y) + 1
table = [[0] * r for _ in range(c)]
for i, j in block:
i, j = i - min(x), j - min(y)
table[i][j] = 1
return table
# ์˜ค๋ฅธ์ชฝ์œผ๋กœ 90๋„ ํšŒ์ „ํ•˜๋Š” ํ•จ์ˆ˜
def rotate(puzzle):
rotate = [[0] * len(puzzle) for _ in range(len(puzzle[0]))]
count = 0
for i in range(len(puzzle)):
for j in range(len(puzzle[i])):
if puzzle[i][j] == 1:
count += 1
rotate[j][len(puzzle) - 1 - i] = puzzle[i][j]
return rotate, count
def solution(game_board, table):
answer = 0
empty_blocks = find_block(game_board, 0)
puzzles = find_block(table, 1)
for empty in empty_blocks:
filled = False
table = make_table(empty)
for puzzle_origin in puzzles:
if filled == True:
break
puzzle = make_table(puzzle_origin)
for i in range(4):
puzzle, count = rotate(puzzle)
if table == puzzle:
answer += count
puzzles.remove(puzzle_origin)
filled = True
break
return answer
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€