문제 링크 : www.acmicpc.net/problem/1463
문제
정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.
- X가 3으로 나누어 떨어지면, 3으로 나눈다.
- X가 2로 나누어 떨어지면, 2로 나눈다.
- 1을 뺀다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
입력
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.
출력
첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.
접근 방법
dp[n] 는 n를 1로 만들기까지 필요한 연산 수이다.
dp[n] = min(dp[n/3], dp[n/2], dp[n-1]) 로 구하는데, 이때 n이 3 또는 2로 나눠지지 않을 경우에는 최소값 후보에서 제외해야한다.
(어떤 수로 초기화해야하는가에 대한 것은 n이 최대(10^6)일 때 n에서 1을 만들기까지 필요한 연산의 최대값으로 초기화해주면 된다. 즉 10^6에서 1씩 빼는 연산으로만 1을 만들때 필요한 연산의 수인 10^6으로 초기화하면 된다. 본인은 혹시 몰라서 그것보다 더 큰수로 초기화했다.)
1부터 9까지 노가다로 구해보자.
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
dp[i] | 0 | 1 | 1 | 2 | 3 | 2 | 3 | 3 | 2 |
그 다음 n=10일때를 생각해보자.
n은 3으로 나눠떨어지지 않으므로
10->5->...
10->9->...
이 두가지 경우를 생각해볼 수 있다.
dp[5] = 3이고 dp[9] = 2이므로 아래 경우로 계산했을 때 최소 연산으로 1을 만들 수 있다.
즉 dp[10] = dp[9] + 1 인 것이다.
#include <iostream>
#include <algorithm>
using namespace std;
int X;
int ans = 1000000;
int dp[1000001] = {0};
//dp[a], dp[b], dp[c] 중 최소값 리턴
int searchMin(int a, int b, int c){
int min1, min2;
if(dp[a]<dp[b]) {
min1 = dp[a];
if(dp[a]<dp[c]) { min2 = dp[a]; }
else min2 = dp[c];
}
else{
min1 = dp[b];
if(dp[b]<dp[c]) { min2 = dp[b];}
else min2 = dp[c];
}
return min2;
}
int main(){
int X; cin >> X;
//n이 3 또는 2로 나눠지지 않을 때 최소값을 계산하는 searchMin()에서 영향을 주지 않기 위해 큰 수로 초기화한다.
for(int i = 0; i<1000001; i++){dp[i] = 10000000;}
int fir=0, sec=0, trd=0, mini=0; dp[0] = 0; dp[1] = 0;
for(int i = 2; i<=X; i++){
fir = i; sec= i; trd = i;
if(i%3 == 0){
fir = i/3;
}
if(i%2 == 0){
sec = i/2;
}
trd = i-1;
mini = searchMin(fir, sec, trd);
dp[i] = mini + 1;
}
cout << dp[X];
return 0;
}
'Algorithm(BOJ) > DP' 카테고리의 다른 글
[C++] 백준 11057번 - 오르막 수 (0) | 2021.02.26 |
---|---|
[C++] 백준 1149번 - RGB 거리 (0) | 2021.02.22 |
[C++] 백준 1912번 - 연속합 (0) | 2021.02.19 |
[C++] 백준 1699번 - 제곱수의 합 (0) | 2021.02.16 |
[C++] 백준 15990번 - 1,2,3 더하기 5 (0) | 2021.02.15 |