알고리즘

[백준] 21611. 마법사 상어와 블리자드

담쏙 2021. 10. 24. 00:58
728x90

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

 

21611번: 마법사 상어와 블리자드

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그, 비바라기 마법을 할 수 있다. 오늘 새로 배운 마법은 블리자드이고, 크기가 N×N인 격자에서 연습하려고 한다. N은 항상 홀수이고, (

www.acmicpc.net

구슬 탐색을 위한 델타값과 블리자드 마법을 위한 델타값이 다르다는 조건을 제대로 안 읽어서 꽤나 고생했던 문제다. 구슬을 일단 큐에 다 담고 터트려주는 방식을 택했는데 당연하게도 Python으로는 시간초과가 난다. PyPy로는 맞았는데, 다른 사람의 풀이를 보니 투포인터를 이용하여 구현한다면 Python으로도 충분히 돌아갈 것 같다.

 

그리고 중간에 인덱스 에러가 났는데 이는 큐가 비어있을 경우가 있기 때문이다. 임시 방편으로 if q: 로 q가 존재할 때만 코드를 실행하도록 했는데, for문을 돌때 새로운 로직을 이용해 개수를 세주는 식으로 고치는 게 나을 듯하다.

 

코드 수정하기는 다음 번에 하도록.... 그래도 이 문제를 풀면서 달팽이 행렬 마스터가 된 것 같다.

import sys
from copy import deepcopy
from collections import deque
input = sys.stdin.readline

# 좌 하 우 상
dy = [0, 1, 0, -1]
dx = [-1, 0, 1, 0]

blizard = [[-1, 0], [1, 0], [0, -1], [0, 1]]

N, M = map(int, input().split())

# 구슬 없으면 0, 상어 0
grid = [list(map(int, input().split())) for _ in range(N)]

magic_shark = [(N+1)//2 - 1, (N+1)//2 - 1]

ans = 0
for _ in range(M):
    # 블리자드 마법 방향 d, 거리 s
    d, s = map(int, input().split())
    # 블리자드로 구슬 파괴
    y, x = magic_shark
    for i in range(s):
        dr, dc = blizard[d-1]
        ny, nx = y+dr, x+dc
        if 0 <= ny < N and 0 <= nx < N:
            grid[ny][nx] = 0
        y, x = ny, nx

    q = deque()
    turn = 0
    dire = 0
    cnt = 0
    move = 1
    y, x = magic_shark
    while True:
        if y == 0 and x == 0:
            break
        ny, nx = y + dy[dire], x + dx[dire]
        if grid[ny][nx]:
            q.append(grid[ny][nx])
        cnt += 1
        if cnt == move:
            dire = (dire + 1) % 4
            turn += 1
            cnt = 0
            if turn % 2 == 0:
                move += 1

        y, x = ny, nx

    # 큐 돌면서 구슬 폭발

    while True:
        if not q:
            break
        isFalse = True
        first_num = q[0]
        num = 1
        new_q = deque()
        for i in range(1, len(q)):
            if first_num != q[i]:
                if num >= 4:
                    ans += first_num * num
                    isFalse = False
                else:
                    for _ in range(num):
                        new_q.append(first_num)
                first_num = q[i]
                num = 1
            else:
                num += 1
        if num >= 4:
            ans += first_num * num
            isFalse = False
        else:
            for _ in range(num):
                new_q.append(first_num)
        q = deepcopy(new_q)
        if isFalse:
            break
    if q:
        new_q = deque()
        first_num = q[0]
        num = 1
        for i in range(1, len(q)):
            if first_num != q[i]:
                new_q.append(num)
                new_q.append(first_num)
                num = 1
                first_num = q[i]
            else:
                num += 1
        new_q.append(num)
        new_q.append(first_num)
        q = deepcopy(new_q)

    grid = [[0]*N for _ in range(N)]
    turn = 0
    dire = 0
    cnt = 0
    move = 1
    y, x = magic_shark
    for idx in range(len(q)):
        if not q:
            break
        if y == 0 and x == 0:
            break
        ny, nx = y + dy[dire], x + dx[dire]
        grid[ny][nx] = q[idx]
        cnt += 1
        if cnt == move:
            dire = (dire + 1) % 4
            turn += 1
            cnt = 0
            if turn % 2 == 0:
                move += 1

        y, x = ny, nx

print(ans)

'알고리즘' 카테고리의 다른 글

[프로그래머스] 비밀지도  (0) 2021.11.26
[백준] 19237. 어른 상어  (0) 2021.10.23
[백준] 19236. 청소년 상어  (0) 2021.10.22
[백준] 16326. 아기 상어  (0) 2021.10.20
[백준] 17619. 개구리 점프  (0) 2021.10.19