[BOJ] Q20057 마법사 상어와 파이어스톰
[BOJ] Q20058 마법사 상어와 파이어스톰
Question
Language: Python
Difficulty: Gold 3~4(예상)
해당 문제의 시뮬레이션에서는 아래의 과정이 연속적으로 이루어진다.
- 부분 구역에 대한 시계 방향 회전
- 인접한 칸에 대한 검증 및 얼음 녹이기
- 모든 반복을 수행한 이후에 가장 큰 얼음 덩어리 찾기
부분 구역에 대한 시계 방향 회전
각각의 부분 구역으로 분할하는 것이 중요하다.
2n의 큰 보드를 2l개로 나눠서 생각해야한다. 이때, 길이가 2l인 부분구역이 각각 행/열에 대해서, 2n-l 만큼씩 있는 것이므로, 이를 잘게 분해해서 생각해보면 된다.
시계 방향에 대한 회전 함수는 아래와 같이 행/열 관계를 생각해보면 쉽게 식을 유추 할 수 있다.
sub_graph[dx][length-dy-1]=graph[start_row+dy][start_col+dx]
각각의 부분 구역에 대해 시계방향 회전을 수행한 후, 기존 배열에 다시 저장해주면 된다.
인접한 칸에 대한 검증 및 얼음 녹이기
특정 칸에 대해서, 인접한 칸을 검사해서, 얼음이 있는 칸이 3개이상이 있는 경우에는 그대로 놔두게 되지만 3개 미만인 경우에는 해당 칸의 얼음의 양을 1 감소시킨다.
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
#범위를 벗어나는 경우
if next_row < 0 or next_row >= 2**N or next_col < 0 or next_col >= 2**N:
continue
#얼음이 없는 칸
if graph[next_row][next_col] ==0:
continue
count+=1
if count >=3:
return True
else:
return False
모든 과정이 끝난 이후, 가장 얼음 덩어리를 찾는다.
문제에 주어진 조건에 따르면, 덩어리는 인접한 칸들이 모여서 이루어진다. 따라서, bfs을 이용해서 component을 찾는 방향으로 접근한다.
Solution
from collections import deque
def rotation(L):
global graph
length=2**L
iteration=2**(N-L)
for row_index in range(iteration):
for col_index in range(iteration):
start_row=row_index*length
start_col=col_index*length
#회전을 진행한 이후의 부분 배열
sub_graph=[[0] * length for _ in range(length)]
for dy in range(length):
for dx in range(length):
sub_graph[dx][length-dy-1]=graph[start_row+dy][start_col+dx]
#생성된 부분 배열을 기존 배열에 배치
for dy in range(length):
for dx in range(length):
graph[start_row+dy][start_col+dx]=sub_graph[dy][dx]
def bfs(visited,start_row,start_col):
queue=deque([(start_row,start_col)])
dy=[-1,0,1,0]
dx=[0,1,0,-1]
components=[]
while queue:
row,col=queue.popleft()
if visited[row][col]:
continue
visited[row][col]=True
components.append((row,col))
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
if next_row < 0 or next_row >=2**N or next_col < 0 or next_col >= 2**N:
continue
if graph[next_row][next_col] ==0:
continue
queue.append((next_row,next_col))
return components
def check_if_adjacent(row,col):
dy=[-1,0,1,0]
dx=[0,1,0,-1]
count=0
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
if next_row < 0 or next_row >= 2**N or next_col < 0 or next_col >= 2**N:
continue
if graph[next_row][next_col] ==0:
continue
count+=1
if count >=3:
return True
else:
return False
def solution():
for L in magics:
if L!=0:
rotation(L)
decreasing_targets=[]
for row in range(2**N):
for col in range(2**N):
if graph[row][col] ==0:
continue
if not check_if_adjacent(row,col):
decreasing_targets.append((row,col))
for row,col in decreasing_targets:
graph[row][col]-=1
visited=[[False] * (2**N) for _ in range(2**N)]
max_size=0
sum_size=0
for row in range(2**N):
for col in range(2**N):
sum_size+=graph[row][col]
if graph[row][col] ==0 or visited[row][col]:
continue
max_size=max(max_size,len(bfs(visited,row,col)))
print(sum_size)
print(max_size)
if __name__ == "__main__":
N,Q=map(int,input().split())
graph=[list(map(int,input().split())) for _ in range(2**N)]
magics=list(map(int,input().split()))
solution()
댓글남기기