728x90

백준 20056_마법사 상어와 파이어볼

시간 제한 1초, 메모리 제한 512MB


# 조건

  • 마법사 상어가 크기가 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. 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
      1. 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
      2. 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
      3. 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
    4. 질량이 0인 파이어볼은 소멸되어 없어진다.

마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.

입력

  • 첫째 줄에 N, M, K가 주어진다.
  • 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다.
  • 서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다.

출력

  • 마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 출력한다.

제한

  • 4 ≤ N ≤ 50
  • 0 ≤ M ≤ N2
  • 1 ≤ K ≤ 1,000
  • 1 ≤ ri, ci ≤ N
  • 1 ≤ mi ≤ 1,000
  • 1 ≤ si ≤ 1,000
  • 0 ≤ di ≤ 7

# 접근 방법

  • 삼성 SW 역량테스트 기출이다 -> 구현 시뮬레이션!
  • 문제를 잘 읽고 조건을 잘 정리하는 것이 관건.
  • fireball과 arr 배열을 만들어주고 배열이 1부터 시작하므로
    • fireball은 r과 c를 -1 씩 해주고 append한다.
  • for 반복문
    • K 만큼 반복하면서
    • while fireball을 통해 모든 fireball을 이동시켜준다. (arr에 추가)
    • 이후, arr을 순회하면서 길이가 2이상인 경우와 1인 경우를 나눠서 구해준다.
  • 2이상인 경우
    • 무게 합, 속력 합, 홀수, 짝수, 전체 개수 변수를 생성해준 후
    • 해당 arr 을 while문을 통해 반복한다.
    • fireball을 pop을 통해 꺼내주고 무게, 속력, 홀짝 카운트를 누적합해준다.
    • 홀의 수 또는 짝의 수가 전체 길이와 같다면 nd = [0 2 4 8]
    • 아니라면 1 3 5 7의 방향을 가지게 되므로 리스트로 생성해준다.
    • 질량합 // 5가 0이라면 소멸, 아니라면 nd 카운트를 순회하면서 fireball에 추가해준다. -> 방향은 nd 값
  • 1인 경우
    • fireball에 그냥 추가해주기
  • 이후 질량 합만 더하면 된다.
import sys  
sys.stdin = open('input.txt')  
from collections import defaultdict  


N, M, K = map(int, input().split())  
arr = [[[] for _ in range(N)] for _ in range(N)]  
fireball = []  
# 방향  
di, dj = [-1, -1, 0, 1, 1, 1, 0, -1], [0, 1, 1, 1, 0, -1, -1, -1]  

for _ in range(M):  
    r, c, m, s, d = map(int, input().split())  
    fireball.append((r-1, c-1, m,s,d))  

for _ in range(K):  
    while fireball:  
        cr, cc, cm, cs, cd = fireball.pop()  
        # 1번과 N번이 연결되어 있으므로 %로 나눠준다.  
        nr = (cr + cs * di[cd]) % N  
        nc = (cc + cs * dj[cd]) % N  
        arr[nr][nc].append([cm, cs, cd])  

    # 2개 이상인지 체크  
    for r in range(N):  
        for c in range(N):  
            if len(arr[r][c]) >= 2:  
                # 4개로 쪼개기  
                val_m, val_s, cnt_odd, cnt_even, cnt = 0, 0, 0, 0, len(arr[r][c])  
                while arr[r][c]:  
                    m, s, d = arr[r][c].pop()  
                    val_m += m  
                    val_s += s  
                    if d % 2:  
                        cnt_odd += 1  
                    else:  
                        cnt_even += 1  
                if cnt_odd == cnt or cnt_even == cnt:  
                    nd = [0, 2, 4, 6]  
                else:  
                    nd = [1, 3, 5, 7]  

                if val_m // 5:  
                    for i in nd:  
                        fireball.append([r, c, val_m//5, val_s//cnt, i])  

            elif len(arr[r][c]) == 1:  
                fireball.append([r, c] + arr[r][c].pop())  

print(sum(i[2] for i in fireball))
728x90