STUDY/Algorithm
[백준] 20056 마법사 상어와 파이어볼 Python
sinawi95
2022. 3. 31. 11:42
728x90
https://www.acmicpc.net/problem/20056
시뮬레이션 문제이다.
알고리즘 순서는 다음과 같다.
1. 입력
1-1. board: 격자 정보, fireballs: 파이어볼 정보
1-2. 0 <= M <= N^2, N <= 50
입력할 때 격자(이차원 배열)에 여러 개의 파이어볼이 들어갈수 있으므로 리스트로 초기화했다.
2. 시뮬레이션 (K번 반복)
2-1. 모든 파이어볼 이동
2-2. 격자에 파이어볼이 있으면 행동
2-2-1. 격자에 파이어볼이 하나만 있는 경우
2-2-2. 두개 이상인 경우
파이어볼 이동하는 건 fireballs에서 정보를 가져와 board에 추가했고, 모든 정보를 추가했으면 파이어볼이 있는 격자에서 작업을 진행했다. 파이어볼이 하나인 경우엔 그대로 fireballs에 추가했고 두개 이상인 경우에만 합쳤다. 두개 이상인 경우 합치는 작업 이후 질량이 0이 될수 있으므로 이를 확인하면서 fireballs에 추가했다.
3. 출력: 남은 파이어볼 질량의 총 합
시뮬레이션이 끝난후 fireballs에 남은 파이어볼이 있으므로 list comprehension을 사용해서 질량만 추출한 리스트를 만들고, 이를 다합친 값을 출력했다.
import sys; input = sys.stdin.readline
d = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]
def main():
# 0 input
N, M, K = map(int, input().split())
fireballs = []
for _ in range(M):
ri, ci, mi, si, di = map(int, input().split())
ri -= 1
ci -= 1
fireballs.append([ri, ci, mi, si, di])
board = [[[] for _ in range(N)] for _ in range(N)]
# 1 simulation
for _ in range(K):
# 1) all fireballs move
while fireballs:
ri, ci, mi, si, di = fireballs.pop()
ri = (ri + d[di][0] * si) % N
ci = (ci + d[di][1] * si) % N
board[ri][ci].append([mi, si, di])
# 2) split fireballs
for r in range(N):
for c in range(N):
if not board[r][c]:
continue
# if len(board[r][c]) >= 1, calculate n
sum_m, sum_s, sum_num = 0, 0, len(board[r][c])
tmp_d = []
while board[r][c]:
mi, si, di = board[r][c].pop()
sum_m += mi
sum_s += si
tmp_d.append(di % 2)
if sum_num > 1:
sum_m //= 5
sum_s //= sum_num
tmp_sum = sum(tmp_d)
if tmp_sum == 0 or tmp_sum == sum_num:
tmp_d = [0, 2, 4, 6]
else:
tmp_d = [1, 3, 5, 7]
else: # sum_num == 1
tmp_d = [di]
# Add fireball in fireballs
if sum_m:
for td in tmp_d:
fireballs.append([r, c, sum_m, sum_s, td])
# 2 output
answer = sum([m for _, _, m, _, _ in fireballs])
print(answer)
if __name__ == "__main__":
main()