3 분 소요

자료구조를 제외한 라이브러리 최대한 사용하지 않고 문제풀기 (필요하면 직접 코딩)

문제

코드트리 고대 문명 유적 탐사

문제 풀이 및 회고

추가적인 연산을 하지 않고 필요한 모듈만 코딩을 해서 코드를 짜보았다.

코드(python)

from collections import deque

def find_remove(board: list) -> list:
    """
    loc에서 시작해서 3개이상 붙어있는 모든 애들 찾기
    """
    remove_things = []
    visited = [[0]*5 for _ in range(5)] # 방문여부 확인하기 위해
    
    dy, dx = [1,-1,0,0], [0,0,1,-1]
    def bfs(loc: list):
        """
        loc에 있는 값과 동일한 곳들이 3개 이상 붙어있으면 결과값에 추가하기
        """
        nonlocal board, dy, dx, visited
        q = deque()
        q.append(loc)
        value = board[loc[0]][loc[1]] # loc 값
        visited[loc[0]][loc[1]] = 1 # 방문처리
        locations = [] # 제거할 곳
        locations.append(loc)
        while q:
            y, x = q.popleft()
            for i in range(4):
                ny, nx = y+dy[i], x+dx[i]
                if ny < 0 or nx < 0 or ny >= 5 or nx >= 5: # 격자 밖이라 고려 X
                    continue
                if visited[ny][nx] == 0 and board[ny][nx] == value: # board에 loc값과 동일하면서 아직 방문 안해봄
                    visited[ny][nx] = 1 # 방문처리
                    q.append([ny, nx]) # 다음 고려할 곳
                    locations.append([ny, nx]) # 지워야할 곳인지 확인하기 위해서 
        
        return locations if len(locations) >= 3 else None # 연결된 곳이 3개 이상이면 지울거임
    
    for i in range(5):
        for j in range(5):
            if visited[i][j] == 0:
                locations = bfs([i,j])
                if locations:
                    remove_things += locations

    return remove_things

def rotate_board(board: list, loc: list, rot: int) -> list:
    """
    5*5 행렬에서 loc 기준으로(loc가 중심점임) 3*3 행렬을 부분적으로 돌리기
    """
    y, x = loc
    result = [board[i][:] for i in range(5)]
    if rot == 90: # 90도 회전
        for i in range(3):
            for j in range(3):
                result[y-1+i][x-1+j] = board[y-1+2-j][x-1+i]
    elif rot == 180: # 180도 회전
        for i in range(3):
            for j in range(3):
                result[y-1+i][x-1+j] = board[y-1+2-i][x-1+2-j]
    elif rot == 270: # 270도 회전
        for i in range(3):
            for j in range(3):
                result[y-1+i][x-1+j] = board[y-1+j][x-1+2-i]
    return result

def show_board(board: list):
    """
    디버깅을 위해 board 보여주는 함수
    """
    for i in range(5):
        print(board[i])
    print("========================================================")
    return None

def find_max(board: list):
    """
    # 유물 갯수 / 회전각도 작은거 / 중심좌표 열(x) 작은거 / 행(y)이 작은거 기준으로 가장 점수가 높은 곳 찾기
    """
    results = [360, 4, 4]
    remove_locations = []
    for i in range(3):
        for j in range(3):
            loc = [i+1, j+1]

            for r in range(3):
                rot_board = rotate_board(board, loc, 90*(r+1))
                rot_locations = find_remove(rot_board)
                if rot_locations:
                    if len(rot_locations) > len(remove_locations): # 유물 갯수 많은거
                        remove_locations = rot_locations
                        results = [90*(r+1), j+1, i+1]
                    # 회전각도 작은거 / 중심좌표 열(x) 작은거 / 행(y)이 작은거
                    elif len(rot_locations) == len(remove_locations) and min(results, [90*(r+1), j+1, i+1]) != results: 
                        remove_locations = rot_locations
                        results = [90*(r+1), j+1, i+1]
    return remove_locations, results


def solution(board: list, k: int, items: list):
    """
    k 회 turn 내에 점수 나는지 확인
    """
    items_idx = 0

    def refill_item(locations:list):
        nonlocal items_idx, items, board
        for loc in locations:
            board[loc[0]][loc[1]] = items[items_idx]
            items_idx += 1
        return None

    #show_board(board)

    cnt = 0
    while cnt != k: # k회 실행
        cnt += 1
        # 탐사 진행.
        remove_locations, info = find_max(board) #회전해서 가장 우선순위 높은 친구 고르기
        if remove_locations == []: # 더 점수를 얻을 유물이 없음
            break
        remove_locations.sort(key=lambda x:(x[1], -x[0]))
        now_score = 0
        board = rotate_board(board, [info[2], info[1]], info[0]) # 유물 얻은 board로 변경
        now_score += len(remove_locations)
        refill_item(remove_locations)
        #show_board(board)

        while True: # 유물 연쇄 획득 과정
            remove_locations = find_remove(board)
            if remove_locations == []: # 더 점수를 얻을 유물이 없음
                break
            remove_locations.sort(key=lambda x:(x[1], -x[0]))
            now_score += len(remove_locations)
            refill_item(remove_locations)
            #show_board(board)
        
        print(now_score, end=" ") #  번째 줄에 각 턴 마다 획득한 유물의 가치의 총합을 공백을 사이에 두고 출력
        #show_board(board)
        

if __name__ == "__main__":
    K, M = map(int, input().split()) # 탐사 반복횟수 K, 벽면에 적힌 유물 조각의 개수 M
    board = [list(map(int, input().split())) for _ in range(5)] # 5개 줄 유물 정보
    items = list(map(int, input().split()))
    solution(board, K, items)

댓글남기기