본문 바로가기

PS

마법사 상어와 토네이도 [삼성 기출]

1. 문제 접근 방법

- 내가 접근한 방법보다 나은 방법을 찾아서 학습했다

- 중요한 포인트가 몇 가지 있다

 

(1) for i in range(2*N-1)

-> 길이가 N일 때, 2*N-1번 회전이 됨을 이렇게 표시하였다

 

(2) d = i % 4

-> d를 0, 1, 2, 3이 번갈아 오도록 표시하였다

 

(3) d == 0 or d == 2

-> 왼쪽 방향, 오른쪽 방향일때만 time을 1 증가시켰다. 

 

(4) left = [(1, 1, 0.01), (-1, 1, 0.01), (1, 0, 0.07), (-1, 0, 0.07), (1, -1, 0.1),
         (-1, -1, 0.1), (2, 0, 0.02), (-2, 0, 0.02), (0, -2, 0.05), (0, -1, 0)]

-> x변화값, y변화값, 비율을 하나의 배열에 묶어서 표현했다

-> 특히, (0, -1, 0)을 맨 끝에 배치했다는 것이 중요하다 

 

(5) right = [(x, -y, z) for x,y,z in left]
     down = [(-y, x, z) for x,y,z in left]
     up = [(y, x, z) for x,y,z in left]

- > 매우 매우 중요한 포인트. 이렇게 함으로써, 코드 구현량을 기하급수적으로 줄일 수 있다.

      효율성을 위해서 반드시 필요한 코드

-> 다만, 방향 전환에 대한 이해가 있어야 하는 코드이다. 

 

(6) def recount(s_x, s_y, direction):
    global ans

    if s_y < 0:
        return
        
    # 3. a, out_sand
    total = 0  # a 구하기 위한 변수
    for dx, dy, z in direction:
        nx = s_x + dx
        ny = s_y + dy
        if z == 0:  # a(나머지)
            new_sand = sand[s_x][s_y] - total
        else:  # 비율
            new_sand = int(sand[s_x][s_y] * z)
            total += new_sand

        if 0 <= nx < N and 0 <= ny < N:  # 인덱스 범위이면 값 갱신
            sand[nx][ny] += new_sand
        else:  # 범위 밖이면 ans 카운트
            ans += new_sand

 

-> direction을 전달해줌으로써, 코드의 구현을 간단히할 수 있다

-> 여기서 나가는 것과 나가지 않는 것을 잘 판단해서 구분해줘야 한다. 

 

 

2. 코드

# 모래 계산하는 함수
def recount(s_x, s_y, direction):
    global ans

    if s_y < 0:
        return
        
    # 3. a, out_sand
    total = 0  # a 구하기 위한 변수
    for dx, dy, z in direction:
        nx = s_x + dx
        ny = s_y + dy
        if z == 0:  # a(나머지)
            new_sand = sand[s_x][s_y] - total
        else:  # 비율
            new_sand = int(sand[s_x][s_y] * z)
            total += new_sand

        if 0 <= nx < N and 0 <= ny < N:  # 인덱스 범위이면 값 갱신
            sand[nx][ny] += new_sand
        else:  # 범위 밖이면 ans 카운트
            ans += new_sand


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

# 2. 방향별 모래 비율 위치
left = [(1, 1, 0.01), (-1, 1, 0.01), (1, 0, 0.07), (-1, 0, 0.07), (1, -1, 0.1),
         (-1, -1, 0.1), (2, 0, 0.02), (-2, 0, 0.02), (0, -2, 0.05), (0, -1, 0)]
right = [(x, -y, z) for x,y,z in left]
down = [(-y, x, z) for x,y,z in left]
up = [(y, x, z) for x,y,z in left]

s_x, s_y = N//2, N//2
ans = 0
dx = [0, 1, 0, -1]
dy = [-1, 0, 1, 0]

# 1.토네이도 회전 방향(y위치)
dict = {0: left, 1: down, 2: right, 3: up}
time = 0
for i in range(2*N-1):
    # 몫: i//4(타임+1), 나머지:i%4(방향)
    d = i % 4
    
    
    if d == 0 or d == 2:  # 다음 회차(d==0) 이거나 right(d==2) 이면 한번 더
        time += 1
    
    for _ in range(time):
        n_x = s_x + dx[d]
        n_y = s_y + dy[d]
        recount(n_x, n_y, dict[d])  # y좌표, 방향
        s_x, s_y = n_x, n_y

print(ans)