코딩테스트

[백준][구현] 마법사 상어와 파이어볼

pythaac 2022. 4. 25. 22:30
BAEKJOON Online Judge(BOJ) 문제입니다.

https://www.acmicpc.net/

 

Baekjoon Online Judge

Baekjoon Online Judge 프로그래밍 문제를 풀고 온라인으로 채점받을 수 있는 곳입니다.

www.acmicpc.net

 

문제

https://www.acmicpc.net/problem/20056

 

20056번: 마법사 상어와 파이어볼

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

www.acmicpc.net

 

내가 작성한 코드

from collections import defaultdict

dir = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]

def read_data():
    N, M, K = map(int, input().rstrip().split())
    fireball = defaultdict(list)
    for _ in range(M):
        r, c, m, s, d = map(int, input().rstrip().split())
        fireball[r-1, c-1].append((m, s, d))
    return N, K, fireball

def move_fireball(N, fireball):
    def move(_r, _c, d, s):
        nw_r, nw_c = _r + (dir[d][0] * s), _c + (dir[d][1] * s)

        if nw_r >= N:
            nw_r %= N
        if nw_c >= N:
            nw_c %= N
        if nw_r < 0:
            nw_r = N-(abs(nw_r) % N) if abs(nw_r) % N != 0 else 0
        if nw_c < 0:
            nw_c = N-(abs(nw_c) % N) if abs(nw_c) % N != 0 else 0

        return nw_r, nw_c

    nw_fireball = defaultdict(list)

    for pos, lst in fireball.items():
        r, c = pos
        for m, s, d in lst:
            nw_r, nw_c = move(r, c, d, s)
            nw_fireball[(nw_r, nw_c)].append((m, s, d))

    return nw_fireball

def merge_and_divide(fireball):
    def get_Ds(_D):
        o = _D[0] % 2
        for d in _D[1:]:
            if d % 2 != o:
                return [1, 3, 5, 7]
        return [0, 2, 4, 6]

    nw_fireball = defaultdict(list)
    for pos, lst in fireball.items():
        num = len(lst)
        r, c = pos
        if num == 1:
            nw_fireball[(r, c)] = lst
            continue

        Sm = Ss = 0
        D = []
        for m, s, d in lst:
            Sm += m
            Ss += s
            D.append(d)

        nw_m = Sm // 5
        if nw_m == 0:
            continue
        nw_s = Ss // num
        nw_D = get_Ds(D)
        for nw_d in nw_D:
            nw_fireball[(r, c)].append((nw_m, nw_s, nw_d))

    return nw_fireball

def get_answer(N, K, fireball):
    _fireball = fireball
    for _ in range(K):
        _fireball = move_fireball(N, _fireball)
        _fireball = merge_and_divide(_fireball)

    answer = 0
    for pos, lst in _fireball.items():
        for m, s, d in lst:
            answer += m
    return answer

def test():
    N = 50
    K = 1
    fireball = defaultdict(list)
    fireball[(1, N-2)].append((1, 1+N, 1))
    fireball[(N-1, 0)].append((1, 1+N, 5))

    # N = 1
    # K = 1
    # fireball = defaultdict(list)

    return N, K, fireball


N, K, fireball = read_data()
# N, K, fireball = test()
print(get_answer(N, K, fireball))
  • 격자가 이어진 경우 좌표 구하기
    • N개의 격자에서 1, 2, ... , N, 1, 2로 이어짐
    • 계산한 r이 N보다 클 때
      - r %= N
    • 계산한 r이 0보다 작을 때
      - r = N - (abs(r) % N) if abs(r) % N != 0 else 0
    • N = 50이고 r이 -50이면
      - N - (abs(r) %N) = 50
      - 따라서 N으로 나누어 떨어질 때 처리가 필요

 

다른 사람이 작성한 코드

None
  • 강한 구현문제로 다른 코드를 참고하지 않음

 

기억해야할 것

  • 엣지 검증
    • 계산 값의 엣지는 항상 체크할 것