몸과 마음이 건전한 SW 개발자

백준 GOLD 3 [20057번] 마법사 상어와 토네이도 {언어 : Python} 본문

알고리즘

백준 GOLD 3 [20057번] 마법사 상어와 토네이도 {언어 : Python}

스위태니 2024. 2. 26. 19:40

문제 링크

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

 

20057번: 마법사 상어와 토네이도

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을

www.acmicpc.net

정답 코드

import sys
input = sys.stdin.readline

# 토네이도 방향에 따른 비율
tornadoDirections = {
    "L": {
        "dr": 0,
        "dc": -1,
        "list": [(0, -2, 0.05), (-1, -1, 0.1), (1, -1, 0.1), (-1, 0, 0.07), (1, 0, 0.07), (-2, 0, 0.02), (2, 0, 0.02), (-1, 1, 0.01), (1, 1, 0.01)]
        },
    "D": {
        "dr": 1,
        "dc": 0,
        "list": [(2, 0, 0.05), (1, -1, 0.1), (1, 1, 0.1), (0, 1, 0.07), (0, -1, 0.07), (0, 2, 0.02), (0, -2, 0.02), (-1, 1, 0.01), (-1, -1, 0.01)]
        },
    "R": {
        "dr": 0,
        "dc": 1,
        "list": [(0, 2, 0.05), (-1, 1, 0.1), (1, 1, 0.1), (1, 0, 0.07), (-1, 0, 0.07), (-2, 0, 0.02), (2, 0, 0.02), (-1, -1, 0.01), (1, -1, 0.01)]
        },
    "U": {
        "dr": -1,
        "dc": 0,
        "list": [(-2, 0, 0.05), (-1, 1, 0.1), (-1, -1, 0.1), (0, 1, 0.07), (0, -1, 0.07), (0, -2, 0.02), (0, 2, 0.02), (1, -1, 0.01), (1, 1, 0.01)]
        }
}

def isValid(nr, nc):
    return 0 <= nr < N and 0 <= nc < N

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



# 토네이도 방향 (왼쪽부터)
directionList = ["L", "D", "R", "U"]
# 일부러 3으로 하고 바로 바꿀 수 있게
nowDirection = 3
# 방향에 따른 중심점 움직이기


# 토네이도 길
tornadoWay = []
for num in range(1, N):
    for _ in range(2):
        tornadoWay.append(num)
tornadoWay.append(N-1)

# 모래 옮기기
sr = sc = N // 2
# 실행
outSand = 0
for tw in tornadoWay:
    # tw가 바뀔 때 마다 방향 전환
    nowDirection = (nowDirection + 1) % 4
    currentD = directionList[nowDirection]
    for _ in range(tw):
        # 옮겨야할 리스트
        lst = tornadoDirections[currentD]["list"]
        # 옮겨야할 거리
        dr = tornadoDirections[currentD]["dr"]
        dc = tornadoDirections[currentD]["dc"]
        # 옮길 모래 위치와 모래 양
        sr += dr
        sc += dc
        currentSand = sand[sr][sc]
        moveSand = 0
        for drr, dcc, percent in lst:
            nr = sr + drr
            nc = sc + dcc
            tmp = int(currentSand * percent)
            moveSand += tmp
            if isValid(nr, nc):
                sand[nr][nc] += tmp
            else:
                outSand += tmp
        # 움직이고 남은 sand
        sand[sr][sc] = 0
        # a에 위치할 sand
        nextR = sr + dr
        nextC = sc + dc
        if isValid(nextR, nextC):
            sand[nextR][nextC] += currentSand - moveSand
        else:
            outSand += currentSand - moveSand

print(outSand)

풀이 방법

  1. 토네이도 방향에 따른 비율과 모레가 옮겨지는 위치를 JSON 형태로 저장한다.
  2. 방향을 리스트 형태와 index + 1 % 4형태로 만든다.
  3. 토네이도 길을 만드는데 달팽이 문자?의 규칙은 다음과 같다.
    1. 좌 1 하 1 우 2 상 2 좌 3 하 3 우 4 상 4 ... n번째까지 반복
    2. n이 7이면
    3. 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6
    4. 마지막에 n-1 추가
  4. 이제 길에 따라서 모래를 움직이고 outSand를 출력하면 끝
  5. 여기서 주의할점은 a부분은 나머지인 45%가 아니라 모래가 날라가고 남은 양이다.
    1. 따라서 currentSand에서 moveSand를 빼준 양을 a부분에 += 형태로 추가하면 된다.

느낀점

  • 오랜만에 풀었지만 쉬운 문제였다.
  • 실수가 잦아서 어디가 틀렸는지 찾기 어려웠는데 결국 방향 부분에서 비율을 잘못 선정한 것이 문제였다.