Step 1: 피로도 계산
어떤 곡갱이를 사용해 광물을 캘 때는 미리 정해진 피로도를 소모합니다.
피로도는 이차원 배열로 미리 구성하면 인덱스를 사용하여 쉽게 접근 할 수 있습니다.
int[][] stamina = new int[][] {{1, 1, 1 }, { 5, 1, 1 }, { 25, 5, 1 }};
List<String> staminaIdx = Arrays.stream(new String[] { "diamond", "iron", "stone" }).toList();
예를 들어 인자 minerals가 { "iron", "diamond", "iron" }인 경우 첫 번째 요소인 iron을 캐낼 때 곡갱이 별로 소모되는 피로도는 다음처럼 구할 수 있습니다.
int staminaIdxOf = staminaIdx.indexOf(minerals[0]);
for (int i = 0; i < 3; ++i)
{
int v = stamina[i][staminaIdxOf];
}
Step 2-1: 광물을 Fragment로 구성
어떤 곡갱이를 선택하더라도 연속되는 광물 5개는 반드시 동일한 곡갱이로 캐내야 합니다.
광물 5개는 하나의 조각(Fragment)로 구성 할 수 있으며 Fragment는 3개의 곡갱이로 캐낼 때의 피로도 미리 계산 할 수 있습니다.
List<Integer[]> fragments = new ArrayList<>();
for (int i = 0; i < minerals.length; ++i)
{
int fragmentId = i / 5;
if (fragmentId >= fragments.size())
fragments.add(new Integer[] { 0, 0, 0 });
int staminaIdxOf = staminaIdx.indexOf(minerals[i]);
for (int j = 0; j < 3; ++j) {
fragments.get(fragmentId)[j] += stamina[j][staminaIdxOf];
}
}
문제에서 제시하는 입력#1은 두 개의 Fragment로 구성됩니다.
Step 2-2: Fragment 구성의 예외적인 중단
인자 picks는 곡갱이 3종류의 수량을 표현합니다. 곡갱이 1개는 광물을 5개 캐낼 수 있으며 더 이상 남아있는 곡갱이가 없으면 Fragment 구성도 중단합니다.
Step 2-1의 Fragment 구성 코드의 반복문에서 잔여 곡갱이 개수를 검사합니다.
int remainPicks = Arrays.stream(picks).sum() * 5;
for (int i = 0; i < minerals.length && 0 < remainPicks; ++i, --remainPicks)
{
int fragmentId = i / 5;
...
}
Step 3: 그리드 알고리즘을 사용하여 최적의 수 계산
이 문제를 푸는 방법은 크게 두 가지입니다.
모든 곡갱이 조합을 사용하는 완전 탐색풀이그리드 알고리즘을 사용하여 풀이
완전 탐색을 사용하게 되면 로직도 복잡해지고 가장 큰 문제는 시간 초과 오류가 발생합니다.
다음 코드에서는 그리드 알고리즘을 사용해서 문제를 해결합니다.
import java.util.*;
class Solution {
public int solution(int[] picks, String[] minerals)
{
int[][] stamina = new int[][] {{1, 1, 1 }, { 5, 1, 1 }, { 25, 5, 1 }};
List<String> staminaIdx = Arrays.stream(new String[] { "diamond", "iron", "stone" }).toList();
List<Integer[]> fragments = new ArrayList<>();
int remainPicks = Arrays.stream(picks).sum() * 5;
for (int i = 0; i < minerals.length && 0 < remainPicks; ++i, --remainPicks)
{
int fragmentId = i / 5;
if (fragmentId >= fragments.size())
fragments.add(new Integer[] { 0, 0, 0 });
int staminaIdxOf = staminaIdx.indexOf(minerals[i]);
for (int j = 0; j < 3; ++j) {
fragments.get(fragmentId)[j] += stamina[j][staminaIdxOf];
}
}
Collections.sort(fragments, (lp, rp) -> {
return rp[2] - lp[2];
});
int answer = 0;
for (Integer[] o : fragments)
{
for (int i = 0; i < picks.length; ++i) {
if (0 < picks[i]) {
answer += o[i];
--picks[i];
break;
}
}
}
return answer;
}
}
코드 | 비고 | |
Fragment를 이때 편차가 가장 큰 |
||
Fragment를 하나 처리 할 때 만약 잔여 곡갱이가 없으면 다음 유형의 곡갱이를 사용합니다. |
더보기
피로도가 높은 Fragment 순서대로 최적의 곡갱이를 선택하는 것이 중요합니다.
'Algorithm > Programmers' 카테고리의 다른 글
Level 2: 요격 시스템, 하나의 축에서 최소한의 교집합 구하기 (0) | 2023.12.07 |
---|---|
Level 1: 카드 뭉치, 배열의 큐잉(Queueing) (0) | 2023.12.06 |
Level 2: PCCP 기출문제 - 석유 시추, BFS 알고리즘 (0) | 2023.12.04 |
Level 1: PCCP 기출 문제 - 데이터 분석, Stream 필터와 정렬 (0) | 2023.12.04 |
Level 1: PCCP 기출문제 - 이웃한 칸, 이중 배열의 랜덤 엑세스 (0) | 2023.12.04 |