본문 바로가기
Python/백준

백준 낚시왕 [17143] 파이썬(Python) 코드 + 해설

by Guardy 2024. 11. 4.
728x90
반응형

백준 17143 낚시왕 문제

문제 설명

낚시왕은 크기가 R×C인 격자판에서 상어 낚시를 한다. 격자판의 각 칸에는 상어가 있을 수 있으며, 상어는 위치 (r,c), 속력 s, 이동 방향 d, 크기 를 가진다.

낚시왕은 첫 번째 열의 왼쪽에 위치하며, 매 초마다 오른쪽으로 한 칸씩 이동한다. 매 시간마다 다음과 같은 일이 발생한다:

  1. 낚시왕이 이동한다.
  2. 낚시왕이 있는 열에서 가장 가까운 상어를 잡는다. 잡은 상어는 격자판에서 사라진다.
  3. 상어들이 이동한다. 각 상어는 자신의 속력과 방향에 따라 이동하며, 격자판의 경계를 넘으면 방향을 반대로 바꾸며 이동을 계속한다.
  4. 같은 칸에 여러 상어가 있다면 크기가 가장 큰 상어만 남고 나머지는 모두 사라진다.

낚시왕이 잡은 상어 크기의 합을 구하는 것이 목표이다.

입력 조건

  • 첫째 줄에 격자판의 크기 R,C와 상어의 수 M이 주어진다. (2≤R,C≤100, 0≤M≤R×C)
  • 다음 M개의 줄에는 상어의 정보가 주어진다.
    • r,c,s,d,z: 상어의 위치 (r,c), 속력 s, 이동 방향 d, 크기 z
    • 방향 d: 1(위), 2(아래), 3(오른쪽), 4(왼쪽)

문제 접근

이 문제는 시뮬레이션 문제로, 시간의 흐름에 따라 상태를 정확하게 업데이트해야 한다. 주요 고려 사항은 다음과 같다:

  • 낚시왕의 이동 및 상어 낚시: 낚시왕은 매 시간마다 오른쪽으로 한 칸씩 이동하며, 현재 열에서 가장 가까운 상어를 잡는다.
  • 상어의 이동: 각 상어는 자신의 속력과 방향에 따라 이동한다. 이동 중에 경계를 넘으면 방향을 반대로 바꾸며 이동한다.
  • 상어의 겹침 처리: 이동 후 같은 칸에 여러 상어가 있다면 크기가 가장 큰 상어만 남긴다.

해결 방법

1. 데이터 구조 정의

  • 상어의 위치와 정보를 저장하기 위해 딕셔너리를 사용한다.
  • 키: 상어의 위치 (x,y)
  • 값: [s,d,z](속력, 방향, 크기)

2. 방향 설정

  • 방향은 다음과 같이 설정한다:
    • 0: 위 (−1,0)
    • 1: 아래 (1,0)
    • 2: 오른쪽 (0,1)
    • 3: 왼쪽 (0,−1)
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]

3. 상어 이동 함수 구현

상어의 이동을 반복문 없이 수학적으로 계산한다.

  • 상어의 이동 주기(cycle)를 계산한다.
    • 세로 이동 주기: cycle=2×(R−1)
    • 가로 이동 주기: cycle=2×(C−1)
  • 속력을 주기로 나눈 나머지를 사용하여 실제 이동 거리를 계산한다.
  • 경계를 넘으면 대칭 위치로 이동하고, 방향을 반대로 바꾼다.
def move_shark(x, y, s, d):
    if d == 0 or d == 1:  # 위 또는 아래
        cycle = 2 * (R - 1)
        s %= cycle
        for _ in range(s):
            x += dx[d]
            if x < 0 or x >= R:
                d = 1 - d
                x += 2 * dx[d]
    else:  # 오른쪽 또는 왼쪽
        cycle = 2 * (C - 1)
        s %= cycle
        for _ in range(s):
            y += dy[d]
            if y < 0 or y >= C:
                d = 5 - d
                y += 2 * dy[d]
    return x, y, d

하지만 위의 함수에서도 반복문이 사용되므로, 반복문을 제거하여 최적화한다.

def move_shark(x, y, s, d):
    if d == 0 or d == 1:  # 세로 이동
        cycle = 2 * (R - 1)
        s %= cycle
        if d == 0:
            x -= s
            if x < 0:
                x = -x
                d = 1
            if x >= R:
                x = cycle - x
                d = 0
        else:
            x += s
            if x >= R:
                x = cycle - x
                d = 0
            if x < 0:
                x = -x
                d = 1
    else:  # 가로 이동
        cycle = 2 * (C - 1)
        s %= cycle
        if d == 2:
            y += s
            if y >= C:
                y = cycle - y
                d = 3
            if y < 0:
                y = -y
                d = 2
        else:
            y -= s
            if y < 0:
                y = -y
                d = 2
            if y >= C:
                y = cycle - y
                d = 3
    return x, y, d

4. 시뮬레이션 진행

  • 낚시왕은 왼쪽에서 시작하여 오른쪽으로 한 칸씩 이동한다.
  • 각 열에서 가장 가까운 상어를 잡고, 잡은 상어의 크기를 누적한다.
  • 상어들을 이동시키고, 이동 후 같은 위치에 있는 상어들은 크기를 비교하여 하나만 남긴다.

 

백준 17143 낚시왕 파이썬 정답 코드

import sys
input = sys.stdin.readline

R, C, M = map(int, input().split())

sharks = dict()

for _ in range(M):
    r, c, s, d, z = map(int, input().split())
    sharks[(r - 1, c - 1)] = [s, d - 1, z]

dx = [-1, 1, 0, 0]  # 위, 아래, 오른쪽, 왼쪽
dy = [0, 0, 1, -1]

def move_shark(x, y, s, d):
    if d == 0 or d == 1:  # 세로 이동
        cycle = 2 * (R - 1)
        if cycle != 0:
            s %= cycle
        if d == 0:
            x -= s
            if x < 0:
                x = -x
                d = 1
            if x >= R:
                x = cycle - x
                d = 0
        else:
            x += s
            if x >= R:
                x = cycle - x
                d = 0
            if x < 0:
                x = -x
                d = 1
    else:  # 가로 이동
        cycle = 2 * (C - 1)
        if cycle != 0:
            s %= cycle
        if d == 2:
            y += s
            if y >= C:
                y = cycle - y
                d = 3
            if y < 0:
                y = -y
                d = 2
        else:
            y -= s
            if y < 0:
                y = -y
                d = 2
            if y >= C:
                y = cycle - y
                d = 3
    return x, y, d

total_catch = 0

for col in range(C):
    # 낚시왕이 있는 열에서 가장 가까운 상어 잡기
    min_row = R
    shark_pos = None
    for row in range(R):
        if (row, col) in sharks:
            if row < min_row:
                min_row = row
                shark_pos = (row, col)
    if shark_pos:
        total_catch += sharks[shark_pos][2]
        del sharks[shark_pos]

    # 상어 이동
    new_sharks = dict()
    for (x, y), (s, d, z) in sharks.items():
        nx, ny, nd = move_shark(x, y, s, d)
        if (nx, ny) in new_sharks:
            if new_sharks[(nx, ny)][2] < z:
                new_sharks[(nx, ny)] = [s, nd, z]
        else:
            new_sharks[(nx, ny)] = [s, nd, z]
    sharks = new_sharks

print(total_catch)

결론

이 문제는 시뮬레이션과 구현 능력을 요구하는 문제로, 각 단계에서 발생하는 상태 변화를 정확히 추적해야 한다. 특히, 상어의 이동에서 반복문을 제거하고 수학적인 계산으로 이동을 처리하여 시간 복잡도를 최적화해야 한다.

17143 백준 제출 결과

 

도움이 되셨다면 공감과 댓글 부탁드립니다.

728x90
반응형