Open ramge132 opened 2 months ago
from collections import deque
import heapq
RELIC_SIZE = 5
DIRECTION = [[-1, 0], [1, 0], [0, -1], [0, 1]]
class RelicValue:
# 첫 번째 단계에서, 최고 우선 순위의 유물을 찾기 위한 클래스
def __init__(self, value, degree, x, y, points, rot_idx):
"""
Args:
value: 유물 개수
degree: 돌린 각도
x: 중점 행 좌표
y: 중점 열 좌표
points: 유물들 좌표
rot_idx: 미리 만들어 놓은 회전 배열의 좌표
"""
self.value = value
self.degree = degree
self.x = x
self.y = y
self.points = points
self.rot_idx = rot_idx
def __lt__(self, other):
# 가치가 높을수록 우선 순위
if self.value > other.value:
return True
elif self.value < other.value:
return False
# 가치가 같다면, 각도가 작을수록 우선 순위
if self.degree < other.degree:
return True
elif self.degree > other.degree:
return False
# 각도가 같다면, 열이 작을수록 우선 순위
if self.y < other.y:
return True
elif self.y > other.y:
return False
# 열이 같아면, 행이 작을수록 우선 순위
if self.x < other.x:
return True
elif self.x > other.x:
return False
class Location:
# 유물을 발굴하고, 남은 공간에 집어 넣기 위한 우선순위 계산
def __init__(self, x, y):
"""
Args:
x: 빈 곳의 행
y: 빈 곳의 열
"""
self.x = x
self.y = y
def __lt__(self, other):
# 열이 작을수록 우선 순위
if self.y < other.y:
return True
elif self.y > other.y:
return False
# 열이 같다면, 행이 클수록 우선 순위
if self.x > other.x:
return True
else:
return False
def __str__(self):
return f"{self.x} - {self.y}"
def bfs_without_replace(loc, relic_map):
"""
BFS를 수행할 때, 기존 유물 지도를 돌리는 것이 아닌, 이미 돌아간 좌표 정보를 활용하여 BFS 수행
Args:
loc: 이미 돌아간 좌표 정보 (5x5)
relic_map: 기존 맵
Returns:
탐색을 통해 얻어낸 유물 개수
유물들의 좌표
"""
num_of_relics = 0
is_visited = set()
queue = deque()
searched_points = []
for i in range(RELIC_SIZE):
for j in range(RELIC_SIZE):
if (i, j) in is_visited:
continue
rot_x, rot_y = loc[i][j]
is_visited.add((i, j))
queue.append((i, j))
temp_searched_points = [(i, j)]
# 좌표만 돌아간 것을 참고한다.
target_color = relic_map[rot_x][rot_y]
cnt = 1
while queue:
x, y = queue.popleft()
for dx, dy in DIRECTION:
temp_x, temp_y = x + dx, y + dy
if (-1 < temp_x < RELIC_SIZE) and (-1 < temp_y < RELIC_SIZE):
if (temp_x, temp_y) in is_visited:
continue
rot_x, rot_y = loc[temp_x][temp_y]
# 좌표만 돌아간 것을 참고한다.
if target_color == relic_map[rot_x][rot_y]:
is_visited.add((temp_x, temp_y))
queue.append((temp_x, temp_y))
temp_searched_points.append((temp_x, temp_y))
cnt += 1
if cnt > 2:
num_of_relics += cnt
searched_points.extend(temp_searched_points)
return num_of_relics, searched_points
def search_relic(rotated_locations, rot_info, relic_map):
"""
모든 회전 경우의 수를 돌아보면서, 가장 큰 유물 조각을 가질 수 있을 때를 확인한다.
Args:
rotated_locations: 미리 회전 시킨 배열 정보
rot_info: RelicValue 인스턴스를 만들기 위한 정보를 사전에 정의한 배열
relic_map: 유물 정보
Returns:
우선 순위에 따라 구해진 가장 많은 유물 수, 바뀐 유물 정보, 발견한 유물 위치 정보
"""
# 우선순위를 위해 heapq 사용
min_heap = []
for idx, loc in enumerate(rotated_locations):
# 매 회전마다 BFS를 수행하여 얻어 낸 유물 개수 등의 정보
num_of_relics, searched_points = bfs_without_replace(loc, relic_map)
# 정보를 heap에 담기
heapq.heappush(min_heap, RelicValue(num_of_relics, *rot_info[idx], searched_points, idx))
# 최종적으로 맨 위에 그 정보가 담기게 됨
result = heapq.heappop(min_heap)
largest_search = result.points
largest_nums = result.value
largest_idx = result.rot_idx
# 해당 회전 경우의 수로 일부분 회전
temp_relic_map = [relic_map[i][:] for i in range(RELIC_SIZE)]
for i in range(RELIC_SIZE):
for j in range(RELIC_SIZE):
rot_x, rot_y = rotated_locations[largest_idx][i][j]
relic_map[i][j] = temp_relic_map[rot_x][rot_y]
return largest_nums, relic_map, largest_search
def repeatedly_search(numbers_on_wall, cnt, relic_map, search_result):
"""
문제에서 2-3단계 반복을 하는 부분으로,
1. 이전에 찾은 유물을 벽에 적힌 번호로 대체하고
2. 다시 BFS를 돌려 유물을 찾는다. (이 때 회전은 없다.)
Args:
numbers_on_wall: 벽에 적힌 번호 리스트
cnt: 벽 번호 순서
relic_map: 유물 정보
search_result: 이전에 얻어 낸 유물 좌표들
Returns:
더 이상 유물을 찾을 수 없는 경우에 반환
연쇄 과정을 통해 구해진 유물의 개수 총 합
유물 정보
벽 순서
"""
ret = 0
loc = [[(x, y) for y in range(RELIC_SIZE)] for x in range(RELIC_SIZE)]
while True:
# 우선, 유물 발굴로 인해 남은 공간을 채운다. -> 우선 순위를 따져 진행한다.
min_heap = []
for x, y in search_result:
heapq.heappush(min_heap, Location(x, y))
# 채우는 과정...
while min_heap:
item = heapq.heappop(min_heap)
x, y = item.x, item.y
relic_map[x][y] = numbers_on_wall[cnt]
cnt += 1 # 벽에 적힌 순서를 따라가도록 하나 씩 증가
# 회전이 없음
num_of_relics, search_result = bfs_without_replace(loc, relic_map)
# 유물을 발견할 수 없다! break
if num_of_relics == 0:
break
ret += num_of_relics
return ret, relic_map, cnt
# 미리 배열을 회전한 정보를 저장해 놓자.
original_loc = [[(x, y) for y in range(RELIC_SIZE)] for x in range(RELIC_SIZE)]
rotated_loc = []
rotation_info = []
for y in range(RELIC_SIZE - 2, 0, -1):
for x in range(RELIC_SIZE - 2, 0, -1):
new_loc = [original_loc[i][:] for i in range(RELIC_SIZE)]
# 일부분을 가져와 돌린다.
partial = [row[y - 1:y + 2] for row in new_loc[x - 1:x + 2]]
for rot in range(1, 5):
# 4번 돌리면 원위치가 되기 때문에, 4번 회전한다.
partial = list(map(list, zip(*partial)))[::-1]
for _x in range(x - 1, x + 2):
for _y in range(y - 1, y + 2):
new_loc[_x][_y] = partial[_x - (x - 1)][_y - (y - 1)]
if rot < 4:
rotated_loc.append([new_loc[i][:] for i in range(RELIC_SIZE)])
# 우선 순위를 표현하기 위해 각도는 -1을 곱한다.
rotation_info.append((rot * -1, x, y))
K, M = list(map(int, input().split()))
input_relic = [list(map(int, input().split())) for _ in range(RELIC_SIZE)]
input_numbers = list(map(int, input().split()))
wall_count = 0
answer_list = []
for k_iter in range(K):
answer = 0
# 1. 탐사 진행) 중심점을 잡고 회전시키면서 유물을 탐색한다.
ret1, input_relic, searched_loc = search_relic(rotated_loc, rotation_info, input_relic)
answer += ret1
# 2. 반복하면서, 유물을 찾자!
ret2, input_relic, wall_count = repeatedly_search(input_numbers, wall_count, input_relic, searched_loc)
answer += ret2
if answer == 0:
break
answer_list.append(answer)
for item in answer_list:
print(item, end=" ")
print()
from collections import deque
# 상 우 하 좌
dxy = [[0, -1], [1, 0], [0, 1], [-1, 0]]
# 회전 시킨 후 획득 가능한 유물 개수
def canGet(matrix_for_find, explore_list, position, rotating_degree, after_rotating=True):
# 최종 가져올 유물들
visited = [[False]*5 for _ in range(5)]
count = 0
# bfs 돌릴 좌표들 하나씩 큐에 담고 bfs
for x, y in explore_list:
# 한 bfs당 유물들 임시 방문처리
temp_visited = [[False]*5 for _ in range(5)]
temp_visited[y][x] = True
queue = deque([(x, y)])
temp_cnt = 1
while queue:
cx, cy = queue.popleft()
for dx, dy in dxy:
nx, ny = cx + dx, cy + dy
# 다음 좌표가 범위를 넘어간 경우
if not (0 <= nx <= 4 and 0 <= ny <= 4):
continue
# 이미 방문한 경우
# 자신의 값과 다른 경우
if visited[ny][nx] or temp_visited[ny][nx] or matrix_for_find[ny][nx] != matrix_for_find[cy][cx]:
continue
# 방문하지 않고 자신과 값이 같다면 추가
else:
queue.append((nx, ny))
temp_visited[ny][nx] = True
temp_cnt += 1
# 연결된 유물이 3개 이상인 경우
if temp_cnt >= 3:
count += temp_cnt
visited = [[visited[j][i] or temp_visited[j][i] for i in range(5)] for j in range(5)]
return count, position, rotating_degree, visited
# 중심 좌표를 지정 해당 좌표를 중심으로 3*3 회전
def rotate(position, rotating_degree):
temp_matrix = [a[:] for a in matrix]
explore_list = set()
# 돌려야 하는 3*3 배열 추출
def getTempArray(position):
temp = []
cx, cy = position
for i in range(-1,2):
temp.append(temp_matrix[cy+i][cx-1:cx+2])
for j in range(-1, 2):
explore_list.add((cx + j, cy + i))
return temp
temp_arr = getTempArray(position)
# 90도 회전
if rotating_degree == 90:
# 2차원 배열을 뒤집어 전치하면 90도 회전
temp_arr = list(zip(*temp_arr[::-1]))
# 180도 회전
elif rotating_degree == 180:
# 2차원 배열을 뒤집어 전치하면 90도 회전
# 해당 회전 2회
for _ in range(2):
temp_arr = list(zip(*temp_arr[::-1]))
# 270도 회전
elif rotating_degree == 270:
# 2차원 배열을 뒤집어 전치하면 90도 회전
# 해당 회전 3회
for _ in range(3):
temp_arr = list(zip(*temp_arr[::-1]))
# 돌린 3*3 배열을 삽입
for i in range(-1, 2):
for j in range(-1, 2):
temp_matrix[position[1]+i][position[0]+j] = temp_arr[i+1][j+1]
# 삽입완료한 5*5배열, bfs 돌릴 시작 좌표 리스트, 중심좌표, 회전 각도를 인자로 bfs함수 실행
rotate_result = canGet(temp_matrix, explore_list, position, rotating_degree)
return rotate_result, temp_matrix
K, M = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(5)]
relics = deque(list(map(int, input().split())))
total_relics = 0
result = []
# 1. 탐사 진행 result의 요소 개수가 탐사 횟수
while len(result) < K:
# 최종 좌표 및 회전 각
max_relics_count = -1
min_rotating_degree = float('inf')
max_rotating_position = (-1, -1)
max_relics_visited = []
max_relics_matrix = []
# 우선순위 고려해서 최종 회전시킬 좌표 및 회전 각 찾기
for y in range(1, 4):
for x in range(1, 4):
for degree in range(90, 271, 90):
(temp_relics, rotating_position, rotating_degree, temp_visited), temp_matrix = rotate((x, y), degree)
# 획득 유물 가장 많은 경우
if temp_relics > max_relics_count:
max_relics_count = temp_relics
min_rotating_degree = rotating_degree
max_rotating_position = rotating_position
max_relics_visited = temp_visited
max_relics_matrix = temp_matrix
# 회전한 각도가 가장 작은 경우
elif temp_relics == max_relics_count and rotating_degree < min_rotating_degree:
max_relics_count = temp_relics
min_rotating_degree = rotating_degree
max_rotating_position = rotating_position
max_relics_visited = temp_visited
max_relics_matrix = temp_matrix
# 열이 작거나 같은 경우
elif temp_relics == max_relics_count and rotating_degree == min_rotating_degree and rotating_position[0] <= max_rotating_position[0]:
# 열이 작은 경우
if rotating_position[0] < max_rotating_position[0]:
max_relics_count = temp_relics
min_rotating_degree = rotating_degree
max_rotating_position = rotating_position
max_relics_visited = temp_visited
max_relics_matrix = temp_matrix
# 행이 작은 경우
elif rotating_position[1] < max_rotating_position[1]:
max_relics_count = temp_relics
min_rotating_degree = rotating_degree
max_rotating_position = rotating_position
max_relics_visited = temp_visited
max_relics_matrix = temp_matrix
# 탐사 후 발견된 유물이 0개인 경우 탐사 종료
if max_relics_count == 0:
break
total_relics += max_relics_count
# 유물 채우기
for i in range(5):
for j in range(4, -1, -1):
if max_relics_visited[j][i]:
max_relics_matrix[j][i] = relics.popleft()
matrix = [a[:] for a in max_relics_matrix]
while True:
# 연쇄 유물 획득
temp_relics, rotating_position, rotating_degree, temp_visited = canGet(matrix, {(i, j) for i in range(5) for j in range(5)}, (-1, -1), 0, after_rotating=False)
# 유물을 획득한 경우
if temp_relics:
total_relics += temp_relics
# 유물 채우기
for i in range(5):
for j in range(4, -1, -1):
if temp_visited[j][i]:
matrix[j][i] = relics.popleft()
# 유물을 획득하지 못한 경우
else:
result.append(str(total_relics))
total_relics = 0
break
print(" ".join(result))
import sys
sys.stdin = open('input.txt')
from collections import deque
def rotate_subgrid(grid, i, j, angle):
# 3×3 부분 그리드 추출
subgrid = [row[j:j + 3] for row in grid[i:i + 3]]
'''
회전 규칙:
90도 회전: (row, col) → (n - 1 - col, row)
180도 회전: (row, col) → (n - 1 - row, n - 1 - col)
270도 회전: (row, col) → (col, n - 1 - row)
'''
if angle == 90:
rotated = [[subgrid[2 - col][row] for col in range(3)] for row in range(3)]
elif angle == 180:
rotated = [[subgrid[2 - row][2 - col] for col in range(3)] for row in range(3)]
elif angle == 270:
rotated = [[subgrid[col][2 - row] for col in range(3)] for row in range(3)]
else:
rotated = subgrid # 무회전슛
# 회전된 부분 그리드를 원래 그리드에 반영
for row in range(3):
for col in range(3):
grid[i + row][j + col] = rotated[row][col]
def find_connected_pieces(grid):
# 상하좌우로 연결된 같은 숫자의 조각을 찾음
visited = [[False] * 5 for _ in range(5)]
pieces = []
for i in range(5):
for j in range(5):
if not visited[i][j]:
num = grid[i][j] # 현재 좌표값, 연결된 유물 그룹을 찾는 기준
queue = deque() # BFS를 위한 큐 생성
queue.append((i, j)) # 현재 좌표를 큐에 추가
visited[i][j] = True # 현재 좌표를 방문 처리
piece = [(i, j)] # 현재 좌표를 첫 번째 유물 조각으로 추가
# BFS 드가자-
while queue:
x, y = queue.popleft()
# 상 하 좌 우 이동
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
# 그리드 범위 벗어나는지 확인 & 방문 했는지 확인
if 0 <= nx < 5 and 0 <= ny < 5 and not visited[nx][ny]:
# 유물 조각 번호가 같으면
if grid[nx][ny] == num:
visited[nx][ny] = True
queue.append((nx, ny)) # 큐에 추가
piece.append((nx, ny)) # 조각 리스트에 추가 (3개 확인용)
# 조각 리스트의 길이가 3 이상이면
if len(piece) >= 3:
# 조각 좌표들을 조각들 리스트에 추가
pieces.append(piece)
return pieces
def fill_positions(grid, positions, wall_numbers, wall_index):
"""
positions: 유물이 사라진 위치 좌표들이 담긴 리스트. 각 좌표는 (row, col) 형식
"""
# 첫 번째 기준: 열(x[1])이 작은 순서대로 정렬 (오름차순)
# 두 번째 기준: 행(x[0])은 큰 순서대로 정렬 (내림차순)
positions.sort(key=lambda x: (x[1], -x[0]))
for pos in positions:
# 벽에 적힌 유물 번호(wall_numbers)가 다 소진되면 반복 종료
if wall_index >= len(wall_numbers):
break
grid[pos[0]][pos[1]] = wall_numbers[wall_index]
wall_index += 1
return wall_index
def simulate(grid, wall_numbers, wall_index):
# 유물 획득 시뮬레이션 실행
total_value = 0
while True:
pieces = find_connected_pieces(grid)
if not pieces:
break
positions_to_fill = [] # set 대신 list로 처리
for piece in pieces:
total_value += len(piece)
for x, y in piece:
grid[x][y] = 0
positions_to_fill.append((x, y))
wall_index = fill_positions(grid, positions_to_fill, wall_numbers, wall_index)
return total_value, wall_index
K, M = map(int, input().split())
grid = [list(map(int, input().split())) for _ in range(5)]
wall_numbers = list(map(int, input().split()))
wall_index = 0
turn_count = 0
result_list = []
while turn_count < K:
best_total_value = -1
best_rotation = None
for i in range(3):
for j in range(3):
for angle in [90, 180, 270]:
# 그리드 복사 (deepcopy 대신 메모리 효율적인 방법 사용)
temp_grid = [row[:] for row in grid]
rotate_subgrid(temp_grid, i, j, angle)
temp_wall_index = wall_index
temp_total_value, temp_wall_index = simulate(temp_grid, wall_numbers, temp_wall_index)
if temp_total_value > best_total_value:
best_total_value = temp_total_value
best_rotation = (i, j, angle)
elif temp_total_value == best_total_value:
# 회전 각도가 작은 것을 우선 선택
if angle < best_rotation[2]:
best_rotation = (i, j, angle)
elif angle == best_rotation[2]:
# 열이 작은 것을 우선 선택
if j < best_rotation[1]:
best_rotation = (i, j, angle)
elif j == best_rotation[1]:
# 행이 작은 것을 우선 선택
if i < best_rotation[0]:
best_rotation = (i, j, angle)
if best_total_value == 0:
# 유물을 획득할 수 없는 경우 탐사 종료
break
else:
i, j, angle = best_rotation
rotate_subgrid(grid, i, j, angle)
total_value, wall_index = simulate(grid, wall_numbers, wall_index)
result_list.append(total_value)
turn_count += 1
print(' '.join(map(str, result_list)))
결론적으로 위 세가지를 알면 끝이다.
순서는 우선 배제하고 방향과 행,열에 대한 개념을 정의하자.
이것은 forward이다.
이것은 backward이다.
origin을 90도 돌린 그리드를 만든다고 생각해보자. 그럴 경우 저장할 리스트에,
여기서, 뒤에 따질 target이란 첫번째로 append하는 리스트이다. 즉, [7, 4, 1]이 target이다.
origin으로 target을 만드려고 한다.
[7, 4, 1]은 origin을 기준으로 col(열) 그리고 backward(역방향)이다.
우리가 이것을 처음 따지게 됐으므로 순서는 1이다.
(오탈자: 행, 열 : row) append 하게되는 순서는 아래와 같다.
origin에서 이것은 row(행) 그리고 forward(순방향)이다.
두 번째로 따지게 됐으니 순서는 2이다.
우리가 알게된 순서와 행 or 열 그리고 방향을 다음 공식에 대입하면 코드가 완성된다.
def rotate_subgrid(grid, i, j, angle):
# 3×3 부분 그리드 추출
subgrid = [row[j:j + 3] for row in grid[i:i + 3]]
'''
기본틀: subgrid[순서1][순서2]
forward = 행 or 열
backward = (n-1)-(행 or 열)
회전 규칙:
90도 회전: (row, col) → (n - 1 - col, row)
180도 회전: (row, col) → (n - 1 - row, n - 1 - col)
270도 회전: (row, col) → (col, n - 1 - row)
'''
if angle == 90:
rotated = [[subgrid[2 - col][row] for col in range(3)] for row in range(3)]
elif angle == 180:
rotated = [[subgrid[2 - row][2 - col] for col in range(3)] for row in range(3)]
elif angle == 270:
rotated = [[subgrid[col][2 - row] for col in range(3)] for row in range(3)]
else:
rotated = subgrid
사용하는 메모리를 확인하는 방법은 2가지가 있다.
psutil
(외부 라이브러리로서, pip install psutil을 해야함)tracemalloc
(설치 필요 없음)psutil
전체 프로세스의 실제 메모리 사용량(resident set size, RSS)을 반환.
파이썬 인터프리터가 사용하는 메모리, 로드된 라이브러리, 스택, 힙
등
프로그램 실행에 필요한 모든 메모리가 포함됨
⇒ 코딩테스트에서 보는 메모리 제한이 이 값
tracemalloc 파이썬 프로그램에서 동적으로 할당한 메모리(예: 리스트, 딕셔너리, 객체 등)의 메모리 사용량만 추적함
import psutil
import os
def get_memory_usage():
# 현재 실행 중인 파이썬 프로세스의 정보를 가져옴
process = psutil.Process(os.getpid())
# 해당 프로세스의 메모리 정보를 가져옴
mem_info = process.memory_info()
# 메모리 정보 중 실제 메모리 사용량(RSS, Resident Set Size)을 반환 (단위: 바이트)
return mem_info.rss # in bytes
print(f"Current memory usage: {get_memory_usage() / (1024 * 1024)} MB")
"""
바이트값으로 리턴되기 때문에
(1024 * 1024)로 나눠줌
- 1byte * 1024 = KB
- 1byte * 1024 * 1024 = MB
"""
import tracemalloc
# 메모리 추적 시작
tracemalloc.start()
# 프로그램 코드 실행
# 메모리 사용량 측정
current, peak = tracemalloc.get_traced_memory()
print(f"Current memory usage: {current / (1024 * 1024)} MB; Peak: {peak / (1024 * 1024)} MB")
# 메모리 추적 종료
tracemalloc.stop()
# 5*5 격자
# 3*3 격자를 선택해서 회전 -> 회전이 가능한 위치를 선택하도록 한다.
# 회전 함수를 설정 90도로 설정한 후, 2배 3배를 한다. -> 90 180 270
# 획득 가치를 최대화 -> 회전 각도가 제일 작은 것 선택
# 회전 중심 좌표의 열이 가장 작은 구간, 열이 같다면 행이 가장 작은 구간
# 새로운 유물 생성 -> 열 다음 행 for i in range(N-1, -1, -1) for j in range(0, N - 1)
# 유물 연쇄 획득 가능
# 1. 유물 획득이 가능한지 확인
# 2. 회전 -> 유물 획득 확인
# 3. 유물 가능하면 획득 후, 채워놓기
# 4. 유물 획득 가능 확인
# 가능 범위 (1,1) ~ (4,4)
# K 탐사 반복 횟수, M 유물 조각 개수
from collections import deque
from collections import defaultdict
from copy import deepcopy
DXY = [(1, 0), (-1, 0),(0, 1), (0, -1)]
def rotate(matrix, init_i, init_j):
new_matrix = [x[:] for x in matrix] # 복사한 메트릭스를 다시 복사
for i in range(-1, 2):
for j in range(-1, 2):
new_matrix[init_i + j][init_j - i] = matrix[init_i + i][init_j + j]
return new_matrix
def bfs(matrix, visited, i, j, flag):
s_x, s_y = (i, j)
queue = deque([(s_x, s_y)])
tmp_dir = set()
tmp_dir.add((s_x, s_y))
visited.add((s_x, s_y))
count = 1
while queue:
x, y = queue.popleft()
for dx, dy in DXY:
nx, ny = x + dx, y + dy
if 0 <= nx < N and 0 <= ny < N and (nx, ny) not in visited and matrix[x][y] == matrix[nx][ny]:
tmp_dir.add((nx, ny))
visited.add((nx, ny))
count += 1
queue.append((nx, ny))
if count >= 3:
if flag:
for x, y in tmp_dir:
matrix[x][y] = 0
return count
return 0
def chk_matrix(matrix, flag):
# 각 방문 좌표들을 vistied set에 저장
# 탐색을 전체 값에 대해 하지 않고, 회전한 값들에 대해서만 탐색을 하도록 만든다.
# 모든 방향에 대해서 탐색을 진행하도록 한다.
# 탐색을 줄이기 위한 위의 방식에 대한 엣지 케이스
# 만약에 회전을 하지 않는 부분에 연결이 되어있는 케이스는 탐색을 하지 못한다.
# 따라서 모든 좌표를 탐색하도록 설정을 먼저 해본다.
visited = set()
result = 0
for i in range(N):
for j in range(N):
if (i, j) not in visited:
result += bfs(matrix, visited, i, j, flag)
return result
N = 5 # 매트릭스 크기
S = 3 # 회전 크기
K, M = map(int, input().split())
matrix = [list(map(int, input().split()))for _ in range(N)]
pre_number = deque(list(map(int, input().split())))
result = []
for _ in range(K): # 탐색 횟수
max_count = 0
for rotation_count in range(1, 4):
for init_j in range(1, N-1): # 중심 좌표 선택
for init_i in range(1, N-1):
new_matrix = [x[:] for x in matrix] # 깊은 복사
for _ in range(rotation_count): # 회전 횟수 만큼 회전
new_matrix = rotate(new_matrix, init_i, init_j)
# 최대 값을 가지는 matrix를 먼저 확인할 수 있도록 flag 설정
# False는 유물 발굴을 하지 않는다.
tmp_count = chk_matrix(new_matrix, False)
if max_count < tmp_count:
max_count = tmp_count
result_matrix = new_matrix
if max_count == 0:
break
count = 0
# 최종적으로 선택된 matrix를 이용해서 유물 발굴을 시작
while True:
t = chk_matrix(result_matrix, True)
if t == 0:
break
count += t
for j in range(N):
for i in range(4, -1, -1):
if result_matrix[i][j] == 0:
result_matrix[i][j] = pre_number.popleft()
result.append(count)
# 다음 단계를 위해 result_matrix를 원본 matrix에 저장
matrix = result_matrix
print(*result)
https://www.codetree.ai/training-field/frequent-problems/problems/ancient-ruin-exploration/description?page=1&pageSize=20