Algorithm/Baekjoon
[Swift] 2839 설탕배달
내일은개발천재🎵
2023. 3. 22. 14:15
2839 설탕배달
문제 요약
상근이는 정확히 Nkg의 설탕을 배달해야한다. 설탕은 3kg, 5kg의 봉지에 담겨있다. 이때 상근이가 Nkg의 설탕을 최소한의 봉지로 배달하려고 한다. 이때 최소 봉지 수를 계산해라. (정확히 Nkg으로 배달할 수 없을 때에는 -1를 출력한다.)
알고리즘
- 설탕 DP 배열을 선언한다.
- 점화식 $$F(n) = min(F(n-3), F(n-5)) +1$$을 만족하는 F(n)을 계산하여 출력한다.
접근방법
- 그리디로 안 되는 이유?
- 처음에는 그리디로 충분히 접근 가능하다고 생각했다.
- 거스름돈 문제처럼, 5키로 그램 봉지로 나누고, 나머지를 3키로 봉지에 담으면 되지 않나? 라고 생각했지만 아니다!
- 그리디 접근 방식에 따르면, 가능한 만큼 5kg로 가져가고, 나머지를 3kg에 담아야한다.
- 하지만 5는 3의 배수가 아니다. 이에 5를 사용하지 않으면 배달할 수 있지만, 그리디 접근 방법으로 인해 -1이 출력되는 경우가 생긴다.
- 예시 1) 설탕 21kg
- Greedy : 5kg 4개, 남은 설탕 1kg -> 배달 불가, -1 출력
- 실제 정답 : 3kg 7개 -> 배달 가능, 7 출력
- 예시 2) 설탕 11kg
- Greedy: 5kg 1개, 남은 설탕 1kg -> 배달 불가, -1 출력
- 실제 정답: 5kg 1개, 3kg 2개 -> 배달 가능, 3 출력
- 예시 1) 설탕 21kg
- 따라서 이 문제는 그리디로 풀 수 없다.
- 점화식 세우는 방법
- 설탕 11kg으로 생각하면 이렇게 생각할 수 있다.
- 설탕 6kg + 5kg = 11kg
- 설탕 8kg + 3kg = 11kg
- 설탕 8kg을 만들 수 있는지 우선 고려하지 않고, 11kg를 만들 수 있는 경우의 수를 생각하면 된다. (3kg로 만들지 5kg으로 만들지)
- 그리고 설탕 6kg으로 만드는게 더 빠른지, 8kg을 만드는게 더 빠른지 비교하는 것이다. 이후 설탕 봉지 5kg 또는 3kg을 더하면 된다. (+1이 들어가는 이유)
- 그래서 이 점화식이 나오는 것이다. $$F(n) = min(F(n-3), F(n-5)) +1$$
- F(11) = 최소(설탕 8kg 경우의 수, 설탕 6kg 경우의 수) + 1
- 여기서 주의할 점은 F(x)가 -1인 경우는 유효하지 않은 값임을 인지하고 있어야한다.
- 설탕 11kg으로 생각하면 이렇게 생각할 수 있다.
코드
// 설탕 배열 설정
var sugarDP = [-1, -1, -1, 1, -1, 1]
var sugar = Int(readLine()!)!
print(getSugar(sugar))
func getSugar(_ n: Int) -> Int {
// n이 5일 때 까지는 선언된 설탕 배열을 출력한다.
guard n > 5 else { return sugarDP[n] }
// Bottom UP 방식의 DP
for i in 6...n {
let prev1 = sugarDP[i-3]
let prev2 = sugarDP[i-5]
// -1은 유효하지 않은 값이므로 제거 후 정렬한다.
var temp = [prev1, prev2].filter { $0 != -1 }.sorted()
// prev1과 prev2가 모두 -1이었다면, -1을 추가한다.
guard !temp.isEmpty else {
sugarDP.append(-1)
continue
}
// prev1, prev2 중 작은 값에 1을 더해 i를 계산한다.
sugarDP.append(temp[0] + 1)
}
return sugarDP[n]
}