[ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค] ํผ์ฆ์กฐ๊ฐ ์ฑ„์šฐ๊ธฐ (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
    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€