algorithm/Implementation

[백준17143/골드1] 낚시왕 - Python

ayeongjin 2025. 3. 25. 21:16

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

 

매 초마다 기억해야할 것

1. 위치별 상어가 몇마리 들어있는지 (가장 큰 상어가 잡아먹기위해)

2. 각 상어의 속도, 방향, 크기

 

그래서 낚시터 배열 mp 와 상어의 속도, 방향, 크기를 저장할 sharks 딕셔너리를 만들었다.

 

상어 정보 저장

mp = [[[] for _ in range(C)] for _ in range(R)]
sharks = {}
direction = [(-1, 0), (1, 0), (0, 1), (0, -1)]  # 위, 아래, 오른쪽, 왼쪽

for i in range(M):
    r, c, s, d, z = map(int, input().split())  # 위치, 속력, 이동방향, 크기
    heappush(mp[r-1][c-1], (z, i))
    sharks[i] = [s, d-1, z]

 

mp에 상어를 저장할 때는, 같은 위치에 상어가 두 마리 이상 있을 경우 가장 큰상어만 남겨두고 다 없애야 했기 때문에

heap으로 관리하면서 heappop으로 제거하려고 했다.

 

 

그리고 매 초마다 반복할 세가지 함수를 만들었다.

1. 상어 움직이기 함수

2. 같은 위치에 상어가 두마리 이상 있을 경우, 가장 큰 상어가 나머지를 잡아먹는 함수

3. 낚시왕이 상어를 잡는 함수

 

상어 움직이기

def move():
    new_mp = [[[] for _ in range(C)] for _ in range(R)]

    for a in range(R):
        for b in range(C):
        	
            # 해당 위치에 상어 없을 경우 continue
            if not mp[a][b]:
                continue
			
            _, ci = heappop(mp[a][b]) # 상어 크기(샤용안함), 상어 번호
            cs, cd, cz = sharks[ci]   # 해당상어번호(ci)의 속도, 방향, 크기

            na, nb = a, b   # 현재 상어 위치
			
            # 상어 최종 위치 계산
            
            if cd <= 1:  # 위, 아래 방향일 경우
                cycle = (R - 1) * 2   # 상어 이동 가능 범위 (사이클)
                na = (a + cs * direction[cd][0]) % cycle   # 상어 이동
                
                if na >= R:   # 범위 벗어났을 경우 조정
                    na = cycle - na
                    cd = 1 - cd

            else:  # 오른쪽, 왼쪽 방향일 경우
                cycle = (C - 1) * 2   # 상어 이동 가능 범위 (사이클)
                nb = (b + cs * direction[cd][1]) % cycle   # 상어 이동
                
                if nb >= C:   # 범위 벗어났을 경우 조정
                    nb = cycle - nb
                    cd = 5 - cd
			
            # 상어 이동 후, 새로운 위치 저장
            heappush(new_mp[na][nb], (cz, ci))
            sharks[ci] = [cs, cd, cz]

    return new_mp # 새로운 상어 배열 리턴

 

 

같은 위치에 상어가 두 마리 이상 있을 경우, 가장 큰 상어만 남기기

def fight():
    for x in range(R):
        for y in range(C):
        
        	# 해당 위치에 상어가 두마리 이상 있을 경우, 한마리 남을때까지 pop
            while len(mp[x][y]) > 1:
                _, ci = heappop(mp[x][y]) # 해당 위치에서 상어 제거
                sharks.pop(ci)            # 해당 번호의 상어 제거

 

 

낚시왕이 상어 낚시

def fishing(cur): # 낚시왕의 현재 위치 cur

    # 가장 가까운 행 탐색하며 상어 있으면 상어 크기 return
    for r in range(R):
        if mp[r][cur]:
            _, ci = heappop(mp[r][cur])
            size = sharks[ci][2]
            sharks.pop(ci)
            return size
    return 0

 

 

그리고 낚시왕이 열번호 0부터 N-1까지 1초마다 이동하면서 상어 움직이기, 낚시하기 함수를 적용했다.

 

매 초마다 사이클 반복

result = 0

for king in range(C):
    result += fishing(king)
    mp = move()
    fight()

print(result)

 

 

# 성공 코드

import sys
from heapq import heappop, heappush
input = sys.stdin.readline

R, C, M = map(int, input().split())  # 세로, 가로, 상어 수
mp = [[[] for _ in range(C)] for _ in range(R)]
sharks = {}
direction = [(-1, 0), (1, 0), (0, 1), (0, -1)]  # 위, 아래, 오른쪽, 왼쪽

for i in range(M):
    r, c, s, d, z = map(int, input().split())  # 위치, 속력, 이동방향, 크기
    heappush(mp[r-1][c-1], (z, i))
    sharks[i] = [s, d-1, z]


def move():
    new_mp = [[[] for _ in range(C)] for _ in range(R)]

    for a in range(R):
        for b in range(C):

            # 해당 위치에 상어 없을 경우 continue
            if not mp[a][b]:
                continue

            _, ci = heappop(mp[a][b])  # 상어 크기(샤용안함), 상어 번호
            cs, cd, cz = sharks[ci]  # 해당상어번호(ci)의 속도, 방향, 크기

            na, nb = a, b  # 현재 상어 위치

            # 상어 최종 위치 계산

            if cd <= 1:  # 위, 아래 방향일 경우
                cycle = (R - 1) * 2  # 상어 이동 가능 범위 (사이클)
                na = (a + cs * direction[cd][0]) % cycle  # 상어 이동

                if na >= R:  # 범위 벗어났을 경우 조정
                    na = cycle - na
                    cd = 1 - cd

            else:  # 오른쪽, 왼쪽 방향일 경우
                cycle = (C - 1) * 2  # 상어 이동 가능 범위 (사이클)
                nb = (b + cs * direction[cd][1]) % cycle  # 상어 이동

                if nb >= C:  # 범위 벗어났을 경우 조정
                    nb = cycle - nb
                    cd = 5 - cd

            # 상어 이동 후, 새로운 위치 저장
            heappush(new_mp[na][nb], (cz, ci))
            sharks[ci] = [cs, cd, cz]

    return new_mp  # 새로운 상어 배열 리턴


def fight():
    for x in range(R):
        for y in range(C):

            # 해당 위치에 상어가 두마리 이상 있을 경우, 한마리 남을때까지 pop
            while len(mp[x][y]) > 1:
                _, ci = heappop(mp[x][y])  # 해당 위치에서 상어 제거
                sharks.pop(ci)  # 해당 번호의 상어 제거


def fishing(cur): # 낚시왕의 현재 위치 cur

    # 가장 가까운 행 탐색하며 상어 있으면 상어 크기 return
    for r in range(R):
        if mp[r][cur]:
            _, ci = heappop(mp[r][cur])
            size = sharks[ci][2]
            sharks.pop(ci)
            return size
    return 0

result = 0

for king in range(C):
    result += fishing(king)
    mp = move()
    fight()

print(result)

 

 

처음에는 상어 이동을 for문으로 반복하면서 한 칸씩 이동했더니 시간초과났다.

0 <= s (상어 속력) <= 1000인 걸 간과했다.

 

# 실패 코드 (move 함수)

def move():
    new_mp = [[[] for _ in range(C)] for _ in range(R)]

    for a in range(R):
        for b in range(C):
            if not mp[a][b]:
                continue

            _, ci = heappop(mp[a][b])
            cs, cd, cz = sharks[ci]

            na, nb = a, b

            for _ in range(cs):
                tmp_a, tmp_b = na + direction[cd][0], nb + direction[cd][1]

                # 벽에 부딪히면 방향 반전
                if not (0 <= tmp_a < R and 0 <= tmp_b < C):
                    cd = (0 if cd == 1 else 1 if cd == 0 else 2 if cd == 3 else 3)
                    tmp_a, tmp_b = na + direction[cd][0], nb + direction[cd][1]

                na, nb = tmp_a, tmp_b

            heappush(new_mp[na][nb], (cz, ci))
            sharks[ci] = [cs, cd, cz]

    return new_mp