미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.
공기청정기는 항상 1번 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.
1초 동안 아래 적힌 일이 순서대로 일어난다.
다음은 확산의 예시이다.
공기청정기의 바람은 다음과 같은 방향으로 순환한다.
방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.
입력
첫째 줄에 R, C, T (6 ≤ R, C ≤ 50, 1 ≤ T ≤ 1,000) 가 주어진다.
둘째 줄부터 R개의 줄에 Ar,c (-1 ≤ Ar,c ≤ 1,000)가 주어진다. 공기청정기가 설치된 곳은 Ar,c가 -1이고, 나머지 값은 미세먼지의 양이다. -1은 2번 위아래로 붙어져 있고, 가장 윗 행, 아랫 행과 두 칸이상 떨어져 있다.
출력
첫째 줄에 T초가 지난 후 구사과 방에 남아있는 미세먼지의 양을 출력한다.
구현 순서
- 미세먼지가 먼저 확산한다(diffusion)
- 위쪽은 반시계방향, 아래쪽은 시계방향으로 회전한다(rotate)
두 가지를 순서대로 구현하면 되는 구현문제다
풀이1
def speard_dust(dusts, R, C, dust_lst, new_dusts):
dust_lst = FIND_DUST(dusts, R, C)
for dust, amount in dust_lst.items():
r, c = dust
to_amount = amount // 5
if to_amount > 0:
for d in range(4):
dr, dc = SPREAD_DIR[d]
nr, nc = r+dr, c+dc
if -1 < nr < R and -1 < nc < C and dusts[nr][nc] != -1:
new_dusts[nr][nc] += to_amount
amount -= to_amount
new_dusts[r][c] += amount
return new_dusts
풀이2
def diffusion(dusts, R, C):
new_dusts = [[0] * C for _ in range(R)]
for i in range(R):
for j in range(C):
# 공기청정기 피하기
if dusts[i][j] == -1:
new_dusts[i][j] = -1
continue
# 굳이 미세먼지가 없는 부분은 확인하지 않음 왜냐면 많이 반복될수록 미세먼지 없는 칸이 없으므로..
dust = dusts[i][j]
diffusion_dust, diffusion_area = dust // 5, 0
if i+1 < R and dusts[i+1][j] != -1:
new_dusts[i+1][j] += diffusion_dust
diffusion_area += 1
if j+1 < C and dusts[i][j+1] != -1:
new_dusts[i][j+1] += diffusion_dust
diffusion_area += 1
if i-1 > -1 and dusts[i-1][j] != -1:
new_dusts[i-1][j] += diffusion_dust
diffusion_area += 1
if j-1 > -1 and dusts[i][j-1] != -1:
new_dusts[i][j-1] += diffusion_dust
diffusion_area += 1
new_dusts[i][j] += (dust - diffusion_dust * diffusion_area)
return new_dusts
풀이1
# TOP_CLEAN
START_ROW, START_COL = TOP_BOUNDARY, 0
for d in range(4):
dr, dc = TOP_CLEAN[d]
while -1 < START_ROW+dr <= TOP_BOUNDARY and -1 < START_COL+dc < C:
dusts[START_ROW][START_COL], dusts[START_ROW+dr][START_COL+dc] = dusts[START_ROW+dr][START_COL+dc], dusts[START_ROW][START_COL]
START_ROW += dr
START_COL += dc
dusts[TOP_BOUNDARY][1] = 0
# UNDER_CLEAN
START_ROW, START_COL = UNDER_BOUNDARY, 0
for d in range(4):
dr, dc = DOWN_CELAN[d]
while UNDER_BOUNDARY <= START_ROW+dr < R and -1 < START_COL+dc < C:
dusts[START_ROW][START_COL], dusts[START_ROW+dr][START_COL+dc] = dusts[START_ROW+dr][START_COL+dc], dusts[START_ROW][START_COL]
START_ROW += dr
START_COL += dc
dusts[UNDER_BOUNDARY][1] = 0
풀이2
def rotate(dusts, R, C):
# 1열에 있는 미세먼지 이동(공기 청정기 바로 위쪽은 빨려들어가기 때문에 제외)
for i in range(TOP_ROW-2, -1, -1):
dusts[i+1][0] = dusts[i][0]
# 1행에 있는 미세먼지 이동
for j in range(1, C):
dusts[0][j-1] = dusts[0][j]
# C-1열에 있는 미세먼지 이동
for i in range(1, TOP_ROW+1):
dusts[i-1][C-1] = dusts[i][C-1]
# TOP_ROW행에 있는 미세먼지 이동(0열에 있는 공기청정기는 이동할 필요 없음)
for j in range(C-2, 0, -1):
dusts[TOP_ROW][j+1] = dusts[TOP_ROW][j]
dusts[TOP_ROW][1] = 0
for i in range(UNDER_ROW+2, R):
dusts[i-1][0] = dusts[i][0]
for j in range(1, C):
dusts[R-1][j-1] = dusts[R-1][j]
for i in range(R-2, UNDER_ROW-1, -1):
dusts[i+1][C-1] = dusts[i][C-1]
for j in range(C-2, 0, -1):
dusts[UNDER_ROW][j+1] = dusts[UNDER_ROW][j]
dusts[UNDER_ROW][1] = 0
# 3148ms
def FIND_DUST(dusts, R, C):
dust_lst = {}
for i in range(R):
for j in range(C):
if (dust_amount:=dusts[i][j]) > 0:
dust_lst[(i, j)] = dust_amount
return dust_lst
def FIND_CLENADER(dusts, R):
for i in range(R):
if dusts[i][0] == -1:
return i, i+1
def speard_dust(dusts, R, C, dust_lst, new_dusts):
dust_lst = FIND_DUST(dusts, R, C)
for dust, amount in dust_lst.items():
r, c = dust
to_amount = amount // 5
if to_amount > 0:
for d in range(4):
dr, dc = SPREAD_DIR[d]
nr, nc = r+dr, c+dc
if -1 < nr < R and -1 < nc < C and dusts[nr][nc] != -1:
new_dusts[nr][nc] += to_amount
amount -= to_amount
new_dusts[r][c] += amount
return new_dusts
import sys
input = sys.stdin.readline
R, C, T = map(int, input().split())
dusts = [list(map(int, input().split())) for _ in range(R)]
TOP_CLEAN = ((-1, 0), (0, 1), (1, 0), (0, -1))
DOWN_CELAN = ((1, 0), (0, 1), (-1, 0), (0, -1))
SPREAD_DIR = ((1, 0), (0, 1), (-1, 0), (0, -1))
TOP_BOUNDARY, UNDER_BOUNDARY = FIND_CLENADER(dusts, R)
dust_lst = FIND_DUST(dusts, R, C)
for _ in range(T):
new_dusts = [[0] * C for _ in range(R)]
new_dusts[TOP_BOUNDARY][0] = -1
new_dusts[UNDER_BOUNDARY][0] = -1
dusts = speard_dust(dusts, R, C, dust_lst, new_dusts)
# TOP_CLEAN
START_ROW, START_COL = TOP_BOUNDARY, 0
for d in range(4):
dr, dc = TOP_CLEAN[d]
while -1 < START_ROW+dr <= TOP_BOUNDARY and -1 < START_COL+dc < C:
dusts[START_ROW][START_COL], dusts[START_ROW+dr][START_COL+dc] = dusts[START_ROW+dr][START_COL+dc], dusts[START_ROW][START_COL]
START_ROW += dr
START_COL += dc
dusts[TOP_BOUNDARY][1] = 0
# UNDER_CLEAN
START_ROW, START_COL = UNDER_BOUNDARY, 0
for d in range(4):
dr, dc = DOWN_CELAN[d]
while UNDER_BOUNDARY <= START_ROW+dr < R and -1 < START_COL+dc < C:
dusts[START_ROW][START_COL], dusts[START_ROW+dr][START_COL+dc] = dusts[START_ROW+dr][START_COL+dc], dusts[START_ROW][START_COL]
START_ROW += dr
START_COL += dc
dusts[UNDER_BOUNDARY][1] = 0
dust_lst = FIND_DUST(dusts, R, C)
print(sum(dust_lst.values()))
# 1612ms
def FIND_CLENADER(dusts, R):
for i in range(R):
if dusts[i][0] == -1:
return i, i+1
def diffusion(dusts, R, C):
new_dusts = [[0] * C for _ in range(R)]
for i in range(R):
for j in range(C):
# 공기청정기 피하기
if dusts[i][j] == -1:
new_dusts[i][j] = -1
continue
# 굳이 미세먼지가 없는 부분은 확인하지 않음 왜냐면 많이 반복될수록 미세먼지 없는 칸이 없으므로..
dust = dusts[i][j]
diffusion_dust, diffusion_area = dust // 5, 0
if i+1 < R and dusts[i+1][j] != -1:
new_dusts[i+1][j] += diffusion_dust
diffusion_area += 1
if j+1 < C and dusts[i][j+1] != -1:
new_dusts[i][j+1] += diffusion_dust
diffusion_area += 1
if i-1 > -1 and dusts[i-1][j] != -1:
new_dusts[i-1][j] += diffusion_dust
diffusion_area += 1
if j-1 > -1 and dusts[i][j-1] != -1:
new_dusts[i][j-1] += diffusion_dust
diffusion_area += 1
new_dusts[i][j] += (dust - diffusion_dust * diffusion_area)
return new_dusts
def rotate(dusts, R, C):
# 1열에 있는 미세먼지 이동(공기 청정기 바로 위쪽은 빨려들어가기 때문에 제외)
for i in range(TOP_ROW-2, -1, -1):
dusts[i+1][0] = dusts[i][0]
# 1행에 있는 미세먼지 이동
for j in range(1, C):
dusts[0][j-1] = dusts[0][j]
# C-1열에 있는 미세먼지 이동
for i in range(1, TOP_ROW+1):
dusts[i-1][C-1] = dusts[i][C-1]
# TOP_ROW행에 있는 미세먼지 이동(0열에 있는 공기청정기는 이동할 필요 없음)
for j in range(C-2, 0, -1):
dusts[TOP_ROW][j+1] = dusts[TOP_ROW][j]
dusts[TOP_ROW][1] = 0
for i in range(UNDER_ROW+2, R):
dusts[i-1][0] = dusts[i][0]
for j in range(1, C):
dusts[R-1][j-1] = dusts[R-1][j]
for i in range(R-2, UNDER_ROW-1, -1):
dusts[i+1][C-1] = dusts[i][C-1]
for j in range(C-2, 0, -1):
dusts[UNDER_ROW][j+1] = dusts[UNDER_ROW][j]
dusts[UNDER_ROW][1] = 0
import sys
input = sys.stdin.readline
R, C, T = map(int, input().split())
dusts = [list(map(int, input().split())) for _ in range(R)]
TOP_ROW, UNDER_ROW = FIND_CLENADER(dusts, R)
t = 0
while t < T:
dusts = diffusion(dusts, R, C)
rotate(dusts, R, C)
t += 1
answer = 2
for row in dusts:
answer += sum(row)
print(answer)