PS/코드트리

[코드트리] 고대 문명 유적 탐사 (python 정답 코드)

yo0oni 2024. 10. 10. 23:06

https://www.codetree.ai/training-field/frequent-problems/problems/ancient-ruin-exploration/

 

회전각도랑 3x3 회전만 잘 관리하면 엄청 어렵진 않다.. (쉽지도 않다)

회전각도, 행, 열 우선순위도 잘 잡기..

 

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

# 유적지는 5×5
# 유물 조각은 총 7가지 종류로, 각각 숫자 1부터 7로 표현됩니다.
# 3×3 격자를 선택하여 격자를 회전
# 선택된 격자는 시계 방향으로 90도, 180도, 270도 중 하나의 각도만큼 회전

# [1] 3x3 격자 선택
    # 회전
    # (1) 유물 1차 획득 가치를 최대화하고, 그러한 방법이 여러가지인 경우
    # (2) 회전한 각도가 가장 작은 방법을 선택합니다. 그러한 경우도 여러가지인 경우
    # (3) 회전 중심 좌표의 열이 가장 작은 구간을, 그리고 열이 같다면 행이 가장 작은 구간을 선택합니다.

# [2] 유물 획득
    # 인접한 조각들이 3개 이상일 경우
    # 유물의 가치 == 조각의 개수 >= 3

# 유적의 벽면에는 1부터 7 사이의 숫자가 M개
# [3] 유물 채워넣기
    # 열 번호가 작은 순으로 조각이 생겨납니다.
    # 만약 열 번호가 같다면 행 번호가 큰 순으로 조각이 생겨납니다.

    # 유적의 벽면에 써 있는 숫자를 사용한 이후에는 다시 사용할 수 없
    # 다시 유물획득
    # 조각이 3개 이상 연결되지 않아 유물이 될 수 없을 때까지 반복됩니다.

# 총 K 번의 턴에 걸쳐 진행됩니다.
# 유물 얻을 수 없으면 중간에 즉시 종료 -> 출력 ㄴㄴ

K, M = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(5)]
yumul = deque(list(map(int, input().split())))

def turn(si, sj, board):
    new_board = [x[:] for x in board]
    for i in range(3):
        for j in range(3):
            new_board[si + i][sj + j] = board[si + 3 - j - 1][sj + i]
    return new_board

def bfs(board):
    dq = deque()
    visited = [[False] * 5 for _ in range(5)]
    visited[0][0] = True

    total_value = 0
    total_position = []

    for i in range(5):
        for j in range(5):
            dq.append((i, j))
            position = [(i, j)]

            while dq:
                ci, cj = dq.popleft()
                visited[ci][cj] = True

                for di, dj in ((-1, 0), (1, 0), (0, -1), (0, 1)):
                    ni, nj = ci + di, cj + dj

                    if 0 <= ni < 5 and 0 <= nj < 5 and not visited[ni][nj]:
                        if board[ni][nj] == board[ci][cj]:
                            visited[ni][nj] = True
                            dq.append((ni, nj))
                            position.append((ni, nj))

            if len(position) >= 3:
                total_value += len(position)
                total_position += position

    return total_position, total_value

answer = []
for _ in range(K):
    max_value = 0
    total_value = 0
    value_position = []
    max_board = []

    for d in range(1, 4): # 회전
        for j in range(3):
            for i in range(3):

                new_board = [x[:] for x in board]
                for _ in range(d):
                    new_board = turn(i, j, new_board)

                position, value = bfs(new_board)
                if max_value < value:
                    max_value = value
                    value_position = position
                    max_board = new_board

    if max_value == 0:
        break

    while True:
        # answer += 최대 유물 가치
        total_value += max_value

        # 유물 지우기
        for i, j in value_position:
            max_board[i][j] = 0

        # 채워넣기
        for j in range(5):
            for i in range(4, -1, -1):
                if max_board[i][j] == 0:
                    max_board[i][j] = yumul.popleft()

        value_position, max_value = bfs(max_board)

        if max_value == 0:
            break

    answer.append(total_value)
    board = max_board

print(*answer)