boj 21611 - 마법사 상어와 블리자드 (python)

먼지감자·2021년 10월 19일
0

코딩테스트

목록 보기
34/37

문제

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

해결 방법

주어진 조건마다 함수로 만들어서 해결...하려하였으나 런타임 에러
아직 해결 못함.

아이디어

구현 함수 및 변수

  • num_mat : 문제에서 말하는 칸의 번호가 적힌 2차원 행렬 변수

  • blizard_explode : 얼음 파편을 던졌을 때 구슬을 파괴하는 함수. 2차원 형태를 유지한 상태에서 파괴된 구슬의 인덱스 반환

  • move2 : 얼음파편으로 파괴된 구슬자리에 뒤의 구슬 땡겨오는 함수. 2차원 행렬을 1차원으로 만들어서 해결

  • continous_explode : 4개 이상 연속 된 구슬 제거하는 함수. 마찬가지로 1차원인 상태에서 제거

  • after_blizard_2d : 연속된거 모두 제거한 이후에 (구슬 갯수 , 구슬 번호) 순으로 만드는 함수

  • to2d : after_blizard_2d 내에서 1차원 행렬을 2차원으로 만드는 함수

  • answer : continous_explode에서 연속된 구슬 폭발할 때마다 해당 구슬번호 인덱스 증가

전체 코드

# 구슬 : 1,2,3
# 방향 : 위, 아래, 왼, 오 : 1,2,3,4
# 1. 마법 폭발:  방향 d, 거리 s -> 거리 s이하까지 구슬 폭발
# 2. 폭발 후 빈칸 생기면 구슬 이동 -> 다음 칸에 있는 구슬 앞으로 땡겨와
# 3. 연속 폭발 : 4개 이상 연속되면 폭발 -> 빈칸
# 4. 구슬 이동
# 5. 연속 폭발 : 폭발 -> 이동 반복 (연속 폭발 없을 떄까지)

# 6. 구슬 변화 : 연속 구슬 (갯수A, 변화B) -> 2칸씩

N,M = map(int, input().split())
answer = [0] * 4

mat = []
for i in range(N):
    mat.append(list(map(int, input().split())))

# 초기 상어 위치
shark = (N+1)//2 -1

# 행렬 번호 배열 : 오-아-왼-우ㅣ
mv = [[0,1], [1,0], [0,-1], [-1,0]]
num_mat = [[0 for _ in range(N)] for _ in range(N)]
number = N*N -1
x, y = 0,0
step = 4
def check(num_mat, x,y,N):
    if 0 <= x < N and 0 <= y < N and num_mat[x][y] == 0:
        return True
    return False

for n in range(number, 0, -1):
    num_mat[x][y] = n
    if check(num_mat, x+mv[step%4][0], y+mv[step%4][1], N) == False:
        step+=1

    x+=mv[step%4][0]
    y+=mv[step%4][1]
    # print(x,y)


# 마법 방향
magic_direct = [[0,0], [-1,0], [1,0], [0,-1], [0,1]] # _, 위, 아래, 왼, 오

def blizard_explode(shark, d,s):
    global answer, mat

    p_ind = []
    rng = magic_direct[d] * s # ex) 3,0
    for i in range(1, s+1):
        drdc = [magic_direct[d][0] * i, magic_direct[d][1] * i]
        # print(drdc)
        # print(shark+drdc[0], shark+drdc[1])
        mat[shark+drdc[0]][shark+drdc[1]] = 0
        # answer[mat[shark+drdc[0]][shark+drdc[1]]+1] += 1 # 폭발한 구슬 개수 세기
        p_ind.append((shark+drdc[0], shark+drdc[1]))
    return p_ind

def move2(p_ind):
    # 1. 1차원으로 만들고
    # 2. 구슬 앞으로 이동
    # 3. 다시 2차원으로 만들기 -> 어차피 그 다음이 연속된거 삭제니까 1차원으로 다시 안만들어도 됨
    drdc = [[1,0], [0,1], [-1,0], [0,-1]] # 아 오 위 왼
    d1 = []
    # 1.
    for n in range(1, number):
        for ri, row in enumerate(num_mat):
            if n in row:
                r, c = ri, row.index(n)
        if mat[r][c] != 0: # 2.
            d1.append(mat[r][c])

    d1.extend([0]* (number-len(d1))) # 안쪽 부터 바깥쪽까지 + 바깥쪽 0으로 채움
    # print(len(d1))
    # d1.reverse() # 2차원으로 만들때 바깥쪽부터 채우니까 뒤집어
    # print(d1)

    return d1

def to2d(d1):
    # 3. 1차원 행렬을 2차원으로
    # # 1,2,2,3,3,4,4,5,5,n-1,n-1, n-1
    # step= [1]
    # for n in range(N):
    #     step.extend([n,n])
    # step.append(N-1)
    mv = [[0, 1], [1, 0], [0, -1], [-1, 0]] # 우, 하, 좌, 상
    x, y = 0, 0
    step = 4
    d2 = [[0 for _ in range(N)] for _ in range(N)]
    visit = [[0 for _ in range(N)] for _ in range(N)]
    d1.reverse()
    # print(d1)
    for d1_n in d1:
        d2[x][y] = d1_n
        visit[x][y] = 1
        # print(f'now : {x},{y} | next : {x+mv[step%4][0]}, {y+mv[step%4][1]}')
        if not(0 <= x+mv[step%4][0] < N and 0 <= y+mv[step%4][1] < N and visit[x+mv[step%4][0]][y+mv[step%4][1]] == 0):
            # print('step change')
            step += 1

        x += mv[step % 4][0]
        y += mv[step % 4][1]
        # print(x,y)

    # print('d2 after blizard')
    # for v in d2:
    #     print(v)

    return d2

def continous_explode(d1):
    global answer

    lend1 = len(d1)
    do_del = False
    prev = d1[0]
    cnt = 1
    for i in range(1, lend1):
        if prev == d1[i]:
            cnt += 1
        else:
            if cnt >= 4:
                # print(d1)
                # print(f'biz : {d1[i - 1]}, cnt : {cnt}, i: {i}')
                answer[d1[i - 1]] += cnt
                for j in range(i-cnt, i):
                    d1[j] = 0
                # print(f'after del: \n{d1}, answer : \n{answer}')
                cnt = 1
                do_del = True
            else:
                cnt = 1
        prev = d1[i]

    # print(d1, answer)

    new = []
    for d in d1:
        if d != 0:
            new.append(d)

    return new, do_del

def after_blizard_2d(d1):
    # 1. 구슬 갯수, 구슬 번호 순서대로 만들기
    # 2. 다시 2차원으로 만듬 -> 길이 N*N -1 넘어가면 삭제

    # 1.
    new = []
    prev = d1[0]
    lend1 = len(d1)
    cnt = 1
    for i in range(1, lend1):
        if prev == d1[i]:
            cnt +=1
        else:
            new.append(cnt)
            new.append(d1[i-1])
            cnt = 1
        prev = d1[i]
    # 마지막
    new.append(cnt)
    new.append(d1[-1])
    # print(new)

    # 2.
    # print(number, len(new))
    # print(new)
    if len(new) > number:
        new = new[:number]
        # print('del\n', new)
    else:
        new.extend([0] * (number - len(new)))
    #     print('extend\n', new)
    # print(len(new))
    d2 = to2d(new)

    return d2


# 마법 시전
for _ in range(M):
    d,s = map(int, input().split())
    p_ind = blizard_explode(shark, d, s) # 1. 폭발

    # print('magic')
    # for c in mat:
    #     print(c)

    d1 = move2(p_ind) # 2. 구슬 이동

    # 더이상 연속되는거 없을 까지 3,4 반복
    while True:
        d1, do_del = continous_explode(d1) # 3. 연속 삭제
        if do_del == False:
            break
    # print('after continuous explode: ', d1)
    mat = after_blizard_2d(d1)

# print(answer)
print(1*answer[1] + 2 * answer[2] + 3*answer[3])
profile
ML/AI Engineer

0개의 댓글