코딩테스트/프로그래머스

[프로그래머스 Level2] 양궁대회 - 파이썬(Python) - 2022 KAKAO BLIND RECRUITMENT

yejin72 2023. 1. 10. 14:26
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/92342

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제 설명

카카오배 양궁대회가 열렸습니다.
라이언은 저번 카카오배 양궁대회 우승자이고 이번 대회에도 결승전까지 올라왔습니다. 결승전 상대는 어피치입니다.
카카오배 양궁대회 운영위원회는 한 선수의 연속 우승보다는 다양한 선수들이 양궁대회에서 우승하기를 원합니다. 따라서, 양궁대회 운영위원회는 결승전 규칙을 전 대회 우승자인 라이언에게 불리하게 다음과 같이 정했습니다.

  1. 어피치가 화살 n발을 다 쏜 후에 라이언이 화살 n발을 쏩니다.
  2. 점수를 계산합니다.
    1. 과녁판은 아래 사진처럼 생겼으며 가장 작은 원의 과녁 점수는 10점이고 가장 큰 원의 바깥쪽은 과녁 점수가 0점입니다. 
    2. 만약, k(k는 1~10 사이의 자연수)점을 어피치가 a발을 맞혔고 라이언이 b발을 맞혔을 경우 더 많은 화살을 k점에 맞힌 선수가 k 점을 가져갑니다. 단, a = b일 경우는 어피치가 k점을 가져갑니다. k점을 여러 발 맞혀도 k점 보다 많은 점수를 가져가는 게 아니고 k점만 가져가는 것을 유의하세요. 또한 a = b = 0인 경우, 즉, 라이언과 어피치 모두 k점에 단 하나의 화살도 맞히지 못한 경우는 어느 누구도 k점을 가져가지 않습니다.
      • 예를 들어, 어피치가 10점을 2발 맞혔고 라이언도 10점을 2발 맞혔을 경우 어피치가 10점을 가져갑니다.
      • 다른 예로, 어피치가 10점을 0발 맞혔고 라이언이 10점을 2발 맞혔을 경우 라이언이 10점을 가져갑니다.
    3. 모든 과녁 점수에 대하여 각 선수의 최종 점수를 계산합니다.
  3. 최종 점수가 더 높은 선수를 우승자로 결정합니다. 단, 최종 점수가 같을 경우 어피치를 우승자로 결정합니다.

현재 상황은 어피치가 화살 n발을 다 쏜 후이고 라이언이 화살을 쏠 차례입니다.
라이언은 어피치를 가장 큰 점수 차이로 이기기 위해서 n발의 화살을 어떤 과녁 점수에 맞혀야 하는지를 구하려고 합니다.

화살의 개수를 담은 자연수 n, 어피치가 맞힌 과녁 점수의 개수를 10점부터 0점까지 순서대로 담은 정수 배열 info가 매개변수로 주어집니다. 이때, 라이언이 가장 큰 점수 차이로 우승하기 위해 n발의 화살을 어떤 과녁 점수에 맞혀야 하는지를 10점부터 0점까지 순서대로 정수 배열에 담아 return 하도록 solution 함수를 완성해 주세요. 만약, 라이언이 우승할 수 없는 경우(무조건 지거나 비기는 경우)는 [-1]을 return 해주세요.

 

 

 


이 문제는 값이 크지 않아 백트래킹, dfs, bfs, 조합 등 다양한 시도가 가능한 것 같다.

나는 덱 자료구조에 몇 번째 과녁을 쏠 것인지(cur), 현재까지 화살을 쏜 결과물에 대한 리스트(result)를 넣고 bfs를 진행했다.

 

 

 

라이언은 화살을 쏘아야할지 고민하는 과녁의 위치를 이동하며 어피치보다 하나 더(이기기 위한 최소 조건) 화살을 쏘아서 해당 과녁 점수를 가져올지, 해당 과녁 점수를 가져올 생각이 없는 경우라면 손해를 최소화하기 위해 해당 과녁에 화살을 전혀 쏘지 않을지를 결정해야 한다.

 

그래서 아직 화살이 남아있고, 0~9 사이의 과녁의 위치에 서 있다면, tmp를 통해 해당 과녁의 점수를 가져온 후 다음 과녁 위치로 이동하는 경우tmp2를 통해 점수를 가져오지 않고 다음 과녁 위치로 이동하는 경우로 나누어 덱에 각각의 정보를 담았다.

tmp = deepcopy(result)
tmp[cur] = info[cur] + 1
q.append([cur + 1, tmp])
tmp2 = deepcopy(result)
q.append([cur + 1, tmp2])

 

화살은 반드시 n발을 다 쏘아야 한다. 과녁의 위치가 10을 바라보고 있다면, 남는 화살들을 모두 쏘아준다.

elif cur == 10:
    tmp = deepcopy(result)
    tmp[10] = n - sum(result)
    q.append([11, tmp])

 

 

 

라이언은 n개의 화살보다 더 많이 쏠 수 없으므로 그러한 경우는 무시한다.

n개의 화살을 모두 쏘았다면 그 때의 어피치와 라이언의 점수를 계산해 준다. 라이언은 어피치보다 더 많은 점수를 얻게 되었을 때 우승한다. 

answer는 두 사람 간 최대 점수차가 나오는 경우들을 모아두는 리스트이다. 둘의 점수차가 이제까지 확인된 최대 점수차와 같다면 그대로 결과물을 넣고, 최대 점수차보다 크다면 maxGap을 갱신하고 이 이전 결과물들은 초기화한 후 새 결과물을 담는다. 문제 설명에 따르면, 라이언은 가장 큰 점수 차이로 우승해야 하기 때문이다.

if sum(result) > n:
    continue
elif sum(result) == n:
    apeach, ryan = 0, 0
    for i in range(11):
        if info[i] or result[i]:
            if info[i] >= result[i]:
                apeach += 10 - i
            else:
                ryan += 10 - i
        if ryan > apeach:
            if ryan - apeach == maxGap:
                answer.append(result)
            elif ryan - apeach > maxGap:
                maxGap = ryan - apeach
                answer.clear()
                answer.append(result)

 

 

 

다음의 문제 조건으로 인해 answer의 결과물이 하나 이상이라면 answer[-1]을, 그렇지 않다면 [-1]을 반환해 준다.

  • 라이언이 가장 큰 점수 차이로 우승할 수 있는 방법이 여러 가지 일 경우, 가장 낮은 점수를 더 많이 맞힌 경우를 return 해주세요.
  • 라이언이 어떻게 화살을 쏘든 라이언의 점수가 어피치의 점수보다 낮거나 같으면 [-1]을 return 해야 합니다.

 

 

 

 

<< 전체 코드 >>

from collections import deque
from copy import deepcopy

def solution(n, info):
    answer = []
    
    q = deque()
    q.append([0, [0 for _ in range(11)]])
    maxGap = 0
    while q:
        cur, result = q.popleft()
        if sum(result) > n:
            continue
        elif sum(result) == n:
            apeach, ryan = 0, 0
            for i in range(11):
                if info[i] or result[i]:
                    if info[i] >= result[i]:
                        apeach += 10 - i
                    else:
                        ryan += 10 - i
            if ryan > apeach:
                if ryan - apeach == maxGap:
                    answer.append(result)
                elif ryan - apeach > maxGap:
                    maxGap = ryan - apeach
                    answer.clear()
                    answer.append(result)
        elif cur == 10:
            tmp = deepcopy(result)
            tmp[10] = n - sum(result)
            q.append([11, tmp])
        else:
            tmp = deepcopy(result)
            tmp[cur] = info[cur] + 1
            q.append([cur + 1, tmp])
            tmp2 = deepcopy(result)
            q.append([cur + 1, tmp2])
            
    return [-1] if len(answer) == 0 else answer[-1]

 

728x90