<문제의 접근>
이 문제를 Greedy하게만 풀수 있을까? 즉 큰수로 나누어 지면 계속 빼면서 숫자를 구하면 해답일까? 직관적으로 알기 어렵다면 반례를 생각해 보면 된다. 예는 31이 되겠다. 31은 Greedy하게 풀면 25, 1, 1, 1, 1, 1, 1 로 구성되어 총 6개지만, 10, 10, 10, 1로 구성하면 4개로 구성할 수 있다. 따라서 Greedy하게만은 안된다. 그렇다면 DP로만 풀수 있을까? 값의 범위가 $10^{15}$ 로 매우 크기 때문에 배열을 이용해서 단순하게 확장하는 방법으로는 해법에 다가가기 어렵다. 그럼 어떻게 해야한다? 규칙성을 발견해야 한다. 규칙성을 바탕으로 문제를 단순하게 만들 수 있어야 한다. 아래의 글이 도움이 될것 같다.
<코드>
생각보다 간단하게 작성할 수 있는데, 1부터 100까지는 dp로 풀어낼 수 있어야 한다. 아래와 같이 loop를 돌면서 최소값을 갱신해 준다. 나는 1부터 100까지가 아닌 25까지만 구하고 100까지를 유추하려고 하다가 계속 틀렸습니다를 만났다. 생각보다 단순하지 않으니 잘 보는 것이 좋다.
void dp_init() {
dp[1] = 1;
for (int i=2; i<100;i++) {
dp[i] = dp[i-1] + 1;
if (i>=10) dp[i] = min(dp[i], dp[i-10]+1);
if (i>=25) dp[i] = min(dp[i], dp[i-25]+1);
}
}
큰 수부터 작은 수로 진행하면서 코드를 구성하게 되면 생각보다 복잡해 지게 된다. 아래의 코드가 그렇한 예시를 보여준다. 작동은 하지만 생각보다 코드가 복잡해 진다.
ll solve(ll choco) {
ll ans = 0;
if (choco >= arr[15]) return 1;
if (choco >= arr[14]) {
ans += (choco / arr[14]);
choco = choco % arr[14];
}
for (int i=12; i>=0;i=i-2) {
if (choco/arr[i]) {
int temp = choco/arr[i];
ans += dp[temp];
choco = choco % arr[i];
}
}
return ans;
}
작은 수부터 진행하면 아래와 같이 간단한 수식으로 구성할 수 있다. 정말 간결하면서도 필요한 기능이 담겨져 있다. 이렇게 코드를 구성하면 잔 실수가 없다.
int solve(ll choco) {
int ans = 0;
while (choco) {
ans += dp[choco%100];
choco /= 100;
}
return ans;
}
전체 코드를 첨부해 본다.
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
#define fastio cin.tie(0)->sync_with_stdio(0)
using ll = long long;
using matrix = vector<vector<ll>>;
// 특징적으로 1, 25, 100으로 반복되기 때문에 자릿수를 나누어서 구해줘 본다.
vector<int> dp(100, 0); // 꼭 100까지는 dp로 풀어야 한다. 25까지 구하면 틀림
void dp_init() {
dp[1] = 1;
for (int i=2; i<100;i++) {
dp[i] = dp[i-1] + 1;
if (i>=10) dp[i] = min(dp[i], dp[i-10]+1);
if (i>=25) dp[i] = min(dp[i], dp[i-25]+1);
}
}
// 어려운 풀이
ll solve(ll choco) {
ll ans = 0;
if (choco >= arr[15]) return 1;
if (choco >= arr[14]) {
ans += (choco / arr[14]);
choco = choco % arr[14];
}
for (int i=12; i>=0;i=i-2) {
if (choco/arr[i]) {
int temp = choco/arr[i];
ans += dp[temp];
choco = choco % arr[i];
}
}
return ans;
}
// 쉬운 풀이
int solve(ll choco) {
int ans = 0;
while (choco) {
ans += dp[choco%100];
choco /= 100;
}
return ans;
}
int main() {
fastio;
int t;
cin >> t;
dp_init();
for (int i=0; i<t; i++) {
ll choco;
cin >> choco;
cout << solve(choco) << '\n';
}
return 0;
}
다같이 화이팅 해보자~!
'알고리즘 > Dynamic Programming' 카테고리의 다른 글
[DP] 백준 28218 격자 게임 (0) | 2023.11.02 |
---|---|
[DP] BJ_24416, 알고리즘 수업 (0) | 2023.04.22 |
[DFS & DP] BJ_1937, 욕심쟁이 판다 (0) | 2023.03.08 |
[DP] BJ_2775, 부녀회장이 될테야 (0) | 2023.02.26 |