[Python] [BOJ] 마법사 상어와 파이어볼(20056)

긍정왕·2021년 7월 23일
1

Algorithm

목록 보기
55/69
post-thumbnail

💡 문제 해결

  1. 입력받은 파이어볼에 대한 정보를 arr에 저장
  2. 움직이기 전에 새로운 배열과 파이어볼 정보를 저장할 리스트를 생성
  3. 기존의 파이어볼 정보를 기준으로 새로운 배열에 이동 뒤 파이어볼 위치를 저장하고 파이어볼 정보를 갱신
  4. 저장한 새로운 배열과 파이어볼 정보를 기존에 존재하던 arrfireball_infos에 저장
  5. 배열을 순회하며 2개 이상이 위치한 파이어볼에 대한 조건을 처리
  6. 처리 뒤 새롭게 저장될 정보를 tmp_infos에 저장한 뒤 fireball_infos를 다시 갱신
  7. K번의 회수만큼 반복한 뒤 배열내 파이어볼의 질량을 합산 후 출력


🧾 문제 설명

어른 상어가 마법사가 되었고, 파이어볼을 배웠다.

마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 
가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. 
i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 
위치 (r, c)는 r행 c열을 의미한다.

격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 
1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.

파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.

마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.

1. 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
	이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
2. 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
	1. 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
	2. 파이어볼은 4개의 파이어볼로 나누어진다.
	3. 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
		- 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
		- 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
		- 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 
		  그렇지 않으면 1, 3, 5, 7이 된다.

	4. 질량이 0인 파이어볼은 소멸되어 없어진다.
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.

문제보기



🖨 입출력



📝 풀이

import sys


input = sys.stdin.readline
dx, dy = [-1, -1, 0, 1, 1, 1, 0, -1], [0, 1, 1, 1, 0, -1, -1, -1]

def move():
    global fireball_infos, arr
    
    tmp_arr = [[[] for _ in range(N)] for _ in range(N)]
    tmp_infos = []
    for x, y, m, s, d in fireball_infos:
        nx, ny = (x - 1 + dx[d] * s) % N, (y - 1 + dy[d] * s) % N
        tmp_arr[nx][ny].append([m, s, d])
        tmp_infos.append([nx + 1, ny + 1, m, s, d])
    
    fireball_infos = tmp_infos
    arr = tmp_arr
    return


def divide():
    global fireball_infos
    
    tmp_infos = []
    for i in range(N):
        for j in range(N):
            if arr[i][j]:
                if len(arr[i][j]) > 1:
                    sum_m, sum_s = 0, 0
                    ds = []
                    while arr[i][j]:
                        m, s, d = arr[i][j].pop()
                        sum_m += m
                        sum_s += s
                        ds.append('홀수' if d % 2 else '짝수')
                    
                    if sum_m // 5:
                        if ds.count('홀수') == len(ds) or ds.count('짝수') == len(ds):
                            next_ds = [0, 2, 4, 6]
                        else:
                            next_ds = [1, 3, 5, 7]
                        for next_d in next_ds:
                            arr[i][j].append([sum_m // 5, sum_s // len(ds), next_d])
                            tmp_infos.append([i + 1, j + 1, sum_m // 5, sum_s // len(ds), next_d])
                else:
                    tmp_infos.append([i + 1, j + 1, *arr[i][j][0]])
    fireball_infos = tmp_infos
    return


def calc_sum():
    return sum(m for x, y, m, s, d in fireball_infos)



N, M, K = map(int, input().split())
fireball_infos = [list(map(int, input().split())) for _ in range(M)]

arr = [[[] for _ in range(N)] for _ in range(N)]
for x, y, m, s, d in fireball_infos:
    arr[x - 1][y - 1].append([m, s, d])

for _ in range(K):
    move()
    divide()

answer = calc_sum()
print(answer)

profile
Impossible + 땀 한방울 == I'm possible

0개의 댓글