이번 문제는 삼성 기출 문제였다. 시뮬레이션 문제로, 원판의 회전을 표현해야 하기 때문에 deque의 rotate()함수를 사용하였다. 이를 통해 원판의 회전을 쉽게 구현할 수 있었다. 그러나 원판에서 인접한 곳의 수가 같을 경우에 제거하는 과정에서 조금 오랜 시간이 걸렸다.
우선 주변의 숫자를 확인하기 위해 dy, dx 리스트를 정의하였다. 원판모양이기 때문에 x축의 경우에는 인덱스 m의 오른쪽에는 인덱스 0이 와야 하므로, nx의 경우에는 (x+dx[i])%m
의 형태로 주변을 검사하여 인덱스 에러가 나지 않도록, 끝과 끝을 쉽게 검사하도록 하였다. 그리고 원판의 숫자 제거는 한번에 일어나는 과정이므로, 제거해야 할 인덱스를 튜플 형식으로 리스트에 모두 모으고, 한번에 0으로 갱신하는 과정을 진행하였다. 만약 모든 점에서의 인근 수 비교 후, 인덱스가 모이는 리스트가 비어있을 경우에는 원판 위의 모든 수들의 합과 0보다 큰 수의 갯수를 구하고, 이를 통해 평균값을 구하였다. 원판을 순회하며 평균값보다 큰 수는 1 감소, 작은 수는 1 증가를 시켜줬다.
예제 4번만 자꾸 이상한 값이 나와서 확인해본 결과 원판에서 0인 값은 제거된 값이므로 무시하기 위해 제거 리스트에 넣을 때에 board[i][j]
가 0보다 크다는 조건이 들어가야 하는데 빠져있어서 원판의 수를 지울 수 없는 경우에 1증가, 1감소의 과정이 실행되지 않았다. 코드 한줄을 추가하여 문제를 해결할 수 있었다.
제출 시에 ZeroDivisionError가 발생하였고, 평균값을 구하는 과정에서 모든 값이 0일 경우에 0으로 나눠지게 될 때 발생한다는 것을 바로 생각해냈고, 여기에도 if문을 추가하였다.
from collections import deque
n, m, t=map(int, input().split())
board=[deque(list(map(int, input().split()))) for _ in range(n)]
cycle=[]
for _ in range(t):
x, d, k=map(int, input().split())
cycle.append((x-1, d, k))
dy, dx=[0, 1, 0, -1], [1, 0, -1, 0]
def cycling(x, d, k):
if d==0:
d=1
else:
d=-1
for _ in range(k):
board[x].rotate(d)
def removing():
idxs=set()
for i in range(n):
for j in range(m):
tmp_idx=[]
for d in range(4):
ny, nx=i+dy[d], (j+dx[d])%m
if 0<=ny<n and board[ny][nx]>0 and board[ny][nx]==board[i][j]:
tmp_idx.append((ny, nx))
if tmp_idx:
tmp_idx.append((i, j))
for y, x in tmp_idx:
idxs.add((y, x))
if idxs:
for y, x in idxs:
board[y][x]=0
elif not idxs:
avg=0
cnt=0
for i in range(n):
for j in range(m):
if board[i][j]>0:
avg+=board[i][j]
cnt+=1
if cnt>0 and avg>=0:
avg/=cnt
for i in range(n):
for j in range(m):
if board[i][j]>0:
if board[i][j]>avg:
board[i][j]-=1
elif board[i][j]<avg:
board[i][j]+=1
for i in range(t):
cnt=cycle[i][0]+1
cycling(cycle[i][0], cycle[i][1], cycle[i][2])
while cycle[i][0]+cnt<n:
cycling(cycle[i][0]+cnt, cycle[i][1], cycle[i][2])
cnt+=(cycle[i][0]+1)
removing()
answer=0
for i in range(n):
for j in range(m):
answer+=board[i][j]
print(answer)