새소식

Computer Science/코딩테스트 문제 풀이

[삼성코테 2023 상반기] 토끼와 경주

  • -

토끼와 경주 문제보기

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

import sys
import heapq
sys.stdin=open('input.txt','r')
input = sys.stdin.readline

# 토끼 우선순위 큐
rabbit_pq = []
# 각 토끼의 점수를 기록해줍니다.
scores = [0]
# 각 토끼의 이동거리를 기록해줍니다.
pws = [0]
# 각 토끼의 id를 인덱스 번호로 변환해줍니다.
id_to_idx = {}
# 상하좌우 움직이기 
dx=[-1,1,0,0]
dy=[0,0,-1,1]

ans = 0
global is_picked

# 1. 경주 시작 준비 
def ready(inp):
    global N, M, P                  # NxM 격자, P마리 
    N,M,P, *rabits=inp              # rabits=[고유번호,이동거리,고유번호,이동거리...]
    global scores
    scores = [0 for _ in range(P+1)]
    
    for i in range(1,P+1):
        pid=rabits[i*2-2]        # i번째 토끼의 고유 번호
        pw=rabits[i*2-1]         # 토끼가 이동해야할 거리 
        pws.append(pw)
        id_to_idx[pid] = i       # 토끼 고유번호(pid[i])의 순서(i)
        new_rabit=[0, 2, 1, 1, pid] # 점프수, x+y, x,y, 고유번호 순으로 우선순위가 있음 
        heapq.heappush(rabbit_pq, new_rabit) # jump_cnt, x+y, x, y, pid 순서로 우선순위가 앞으로 정렬됨 
        

# 2. 경주 진행 
def proceed(inp):           # inp:6,100 -> K번 반복, 보너스 점수 S
    global is_picked, ans
    K,S=inp # K:K번반복, S:우선순위가 높은 토끼를 골라 점수 S를 더해주게 됩니다.
    
    is_picked = [False] * (P+1) # 각각의 경주에서 토끼가 달렸는지 여부를 기록해줍니다.

    # 2.1 우선순위가 가장 높은 토끼가 결정이 되면 
    # 이 토끼를 i번 토끼라 했을 때 상하좌우 네 방향으로 각각 dis 만큼 이동했을 때의 위치를 구합니다. 
    for _ in range(K):
        jump_cnt, _, x, y, rabbit_pid = heapq.heappop(rabbit_pq)    # 점프수가 가장 우선순위 
        idx = id_to_idx[rabbit_pid]
        dis = pws[idx]              # 지금 토끼의 이동해야할 거리
        
        # 점프수가 가장 작은 토끼부터 이동 
        possible = []                   # 이동 가능한 위치 
        for i in range(4):
            nx = x + (dx[i] * dis)      # 현재위치(x)+상하좌우방향(dx[i])*거리(dis)
            ny = y + (dy[i] * dis)
            while nx<1 or nx>N or ny<1 or ny>M: # 지도보다 크게 움직이면 
                if nx<1:    # 예: 3x3에서 (1,1)가 -2(2칸 움직임)만큼 되어서 nx가 -1이되면 범위를 넘음 
                    nx=(abs(nx) % ((2*N)-2)) + 2    # {1%(2*3-2=4)}+2=3 -> (1,3)
                if nx>N:                  # 예: 3x3에서 (1,1)가 +5(5칸 움직임)만큼 되어서 nx가 6가되면 범위를 넘음 
                    nx=nx % ((2 * N)-2)   # 6 % (2*3-2=4)=2가 됨 -> (1,2)   
                    if nx>N:
                        nx=(2*N) - nx
                if ny<1:
                    ny=(abs(ny) % ((2 * M)-2)) + 2
                if ny>M:
                    ny=ny % ((2 * M)-2)
                    if ny>M:
                        ny = (2*M) - ny
            heapq.heappush(possible, [-(nx+ny),-nx,-ny])    # 다음으로 x+y,x,y가 작은 순으로 우선순위 큐
        # 2.2 구해진 4개의 위치 중 (행 번호 + 열 번호가 큰 칸, 행 번호가 큰 칸, 열 번호가 큰 칸) 
        # 순으로 우선순위를 두었을 때 가장 우선순위가 높은 칸을 골라 그 위치로 해당 토끼를 이동시킵니다. 
        _,nx,ny=heapq.heappop(possible) # 4개의 가능 위치에서 가장 우선순위가 높은 한곳을 고름 
        nx *= -1                # 우선순위 큐때문에 음수로 만들었으니 다시 양수로 만들기
        ny *= -1
        jump_cnt+=1             # 점프 이동 한번 함 
        heapq.heappush(rabbit_pq, [jump_cnt,nx+ny,nx,ny,rabbit_pid])
        is_picked[idx] = True       # 현재 idx 토끼 달림  
        
        # 2.3 이 칸의 위치를 (ri ,ci)라 했을 때 
        # i번 토끼를 제외한 나머지 P−1마리의 토끼들은 전부 ri+ci 만큼의 점수를 동시에 얻게 됩니다.
        for i in range(1,P+1):
            if i == idx:
                continue
            scores[i] += (nx + ny)
            ans = max(ans, scores[i])       # 각 i토끼의 점수들중 가장 높은 점수 선정 

    # 이렇게 K번의 턴 동안 가장 우선순위가 높은 토끼를 뽑아 멀리 보내주는 것을 반복하게 되며, 
    # 이 과정에서 동일한 토끼가 여러번 선택되는 것 역시 가능합니다.
    # ------------------------------------------------------------------------------------------------
    # 2.4 K번의 턴이 모두 진행된 직후에는 
    # (현재 서있는 행 번호 + 열 번호가 큰 토끼, 행 번호가 큰 토끼, 열 번호가 큰 토끼, 고유번호가 큰 토끼) 순으로 
    # 우선순위를 두었을 때 
    Bonus_priority_rabbit = []
    for g in range(P):
        _,xy,x,y,pid=rabbit_pq[g]       # jump_cnt,nx+ny,nx,ny,pid 순서
        idx=id_to_idx[pid]
        if is_picked[idx]:  # 단, 이 경우에는 K번의 턴 동안 한번이라도 뽑혔던 적이 있던 토끼 중 가장 우선순위가 높은 토끼를 골라야만 함에 꼭 유의합니다.
            heapq.heappush(Bonus_priority_rabbit, [-xy, -x, -y, -pid])
    # 2.4-1 가장 우선순위가 높은 토끼를 골라 점수 S를 더해주게 됩니다.
    _, _, _, pid = heapq.heappop(Bonus_priority_rabbit)
    idx = id_to_idx[-pid]
    scores[idx] += S
    ans = max(ans, scores[idx])

# 3. 이동거리 변경 
def modify(inp):
    pid_t, L = inp
    idx = id_to_idx[pid_t]
    pws[idx] *= L

# 4. 최고의 토끼 선정 
def choice():
    print(ans)

if __name__=="__main__":
    Q=int(input())          # 명령의 수 
    for _ in range(Q):
        command, *inp = list(map(int, input().split()))

        if command == 100:
            ready(inp)
        if command == 200:
            proceed(inp)
        if command == 300:
            modify(inp)
        if command == 400:
            choice()
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.