결론: 주어진 수를 3으로 나누거나, 2로 나누거나, 1을 빼서 1로 만들 때, 최종 연산 횟수와 그 연산 과정에 있는 수들을 구하라.
📌 dp[i] = dp[i - 1] + 1 || dp[i / 2] +1 || dp[i / 3] +1
dp[i]
는 i
를 1로 만드는데 드는 최소 연산 횟수를 의미하며, track[i]
는 i
이전의 숫자를 저장하는 역추적 배열이다.
3으로 나누었든, 2로 나누었든, 1을 뺐든, 그 이전의 dp값에서 한 번의 연산의 추가되었다는 의미의 점화식이다.
#include <bits/stdc++.h>
using namespace std;
int n;
int dp[1000001];
int track[1000001];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
dp[1] = 0;
track[1] = 1;
for(int i =2; i <= n; i++){
dp[i] = dp[i - 1] + 1;
track[i] = i - 1;
if(i % 2 == 0 && dp[i / 2] + 1 < dp[i]) {
dp[i] = dp[i / 2] + 1;
track[i] = i / 2;
}
if(i % 3 == 0 && dp[i / 3] + 1 < dp[i]) {
dp[i] = dp[i / 3] + 1;
track[i] = i / 3;
}
}
cout << dp[n]<< "\n";
if(n != 0) cout << n << " ";
while(n != 1){
cout << track[n] << " ";
n = track[n];
}
return 0;
}