본문 바로가기
Python 알고리즘 공부/프로그래머스 코딩테스트 연습

광물 캐기 (python)

by 두 그루 2023. 5. 13.

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

 

프로그래머스

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

programmers.co.kr

문제 설명

마인은 곡괭이로 광산에서 광석을 캐려고 합니다. 마인은 다이아몬드 곡괭이, 철 곡괭이, 돌 곡괭이를 각각 0개에서 5개까지 가지고 있으며, 곡괭이로 광물을 캘 때는 피로도가 소모됩니다. 각 곡괭이로 광물을 캘 때의 피로도는 아래 표와 같습니다.

예를 들어, 철 곡괭이는 다이아몬드를 캘 때 피로도 5가 소모되며, 철과 돌을 캘때는 피로도가 1씩 소모됩니다. 각 곡괭이는 종류에 상관없이 광물 5개를 캔 후에는 더 이상 사용할 수 없습니다.

마인은 다음과 같은 규칙을 지키면서 최소한의 피로도로 광물을 캐려고 합니다.

  • 사용할 수 있는 곡괭이중 아무거나 하나를 선택해 광물을 캡니다.
  • 한 번 사용하기 시작한 곡괭이는 사용할 수 없을 때까지 사용합니다.
  • 광물은 주어진 순서대로만 캘 수 있습니다.
  • 광산에 있는 모든 광물을 캐거나, 더 사용할 곡괭이가 없을 때까지 광물을 캡니다.

즉, 곡괭이를 하나 선택해서 광물 5개를 연속으로 캐고, 다음 곡괭이를 선택해서 광물 5개를 연속으로 캐는 과정을 반복하며, 더 사용할 곡괭이가 없거나 광산에 있는 모든 광물을 캘 때까지 과정을 반복하면 됩니다.

마인이 갖고 있는 곡괭이의 개수를 나타내는 정수 배열 picks와 광물들의 순서를 나타내는 문자열 배열 minerals가 매개변수로 주어질 때, 마인이 작업을 끝내기까지 필요한 최소한의 피로도를 return 하는 solution 함수를 완성해주세요.

 

제한사항

  • picks는 [dia, iron, stone]과 같은 구조로 이루어져 있습니다.
  • 5 ≤ minerals의 길이 ≤ 50

코드

# Lv.2
# 광물 캐기

def solution(picks, minerals):
    # 도구로 캘 수 있는 만큼만 인덱싱
    if sum(picks) * 5 < len(minerals):
        minerals = minerals[:sum(picks) * 5]
    # 각 광물을 5단위로 개수 정리
    minerals_count = []
    for i in range(0, len(minerals) // 5):
        minerals_tmp = minerals[i*5:i*5+5]
        dia_count = minerals_tmp.count("diamond")
        iron_count = minerals_tmp.count("iron")
        stone_count = minerals_tmp.count("stone")
        minerals_count.append([dia_count, iron_count, stone_count])
    if len(minerals) % 5 != 0:
        minerals_tmp = minerals[-(len(minerals) % 5) : len(minerals)]
        # print("last", minerals_tmp)
        dia_count = minerals_tmp.count("diamond")
        iron_count = minerals_tmp.count("iron")
        stone_count = minerals_tmp.count("stone")
        minerals_count.append([dia_count, iron_count, stone_count])
    # 다이아몬드, 철, 돌이 많은 순서대로 정렬
    minerals_count.sort(key=lambda x: (-x[0], -x[1], -x[2]))
    # print(minerals_count)
    # 피로도 계산
    total_stress = 0
    for tmp in minerals_count:
        if picks[0] > 0:
            picks[0] -= 1
            total_stress += (tmp[0] + tmp[1] + tmp[2])
        elif picks[1] > 0:
            picks[1] -= 1
            total_stress += (tmp[0] * 5 + tmp[1] + tmp[2])
        elif picks[2] > 0:
            picks[2] -= 1
            total_stress += (tmp[0] * 25 + tmp[1] * 5 + tmp[2])
    # print('total stress: ', total_stress)
    answer = total_stress
    return answer

 

알고리즘

1. 도구(곡괭이)로 캘 수 있는 광물만 저장한다(아래 설명 첨부)

2. 한 도구로 5개의 광물을 캘 수 있으니 5개로 나누어 각 광물의 개수를 minerals_count에 정리하여 저장한다

3. minerals_count를 다이아몬드, 철, 돌이 많은 순서대로 정리한다

4. 5 묶음의 광물을 다이아몬드, 철, 돌 순서대로 도구를 줄이면서, 해당 도구를 사용하는 스트레스 값을 total_strees에 더한다

5. total_stress을 반환한다

 

피드백

이 문제는 헷갈리는 점이 있었다. 다이아몬드, 철, 돌이 많은 순서대로 정리를 하면 광물의 총 개수가 5의 배수가 아닌 경우에 중간에 광물의 개수가 5개의 묶음이 아닌 경우가 있을 텐데? 그러면 도구는 무조건 이어서 5개의 광물을 캐야 하는 조건에 부합하지 않을 텐데? 같은 의문이 생겼었다. 

그러나 광물을 캐는 순서는 바뀌지 않으며, 도구를 바꾼다는 것을 잊지 말아야 한다. 광물을 스트레스가 최소가 되게 광물의 묶음 순서를 임의로 변경하여 도구의 수를 줄인 것이다. 그러므로 처음에 도구를 이용하여 캘 수 있는 광물을 인덱싱하고, 광물을 묶음별로 sort해도 괜찮은 것이다.

이전에 도구의 수에 따라 광물을 캘 수 있는 여부를 아래와 같이 확인하였다가 테스트 제출 시에 하나가 통과되지 못했었다.

https://github.com/soaringwave/Python-algorithm-studying/commit/832dbe1e2b3e2b864515b3d53d5790bb83555824


https://github.com/soaringwave/Python-algorithm-studying/blob/main/programmers/Lv.2/mine_stress.py

 

GitHub - soaringwave/Python-algorithm-studying: python study

python study. Contribute to soaringwave/Python-algorithm-studying development by creating an account on GitHub.

github.com

 

댓글