본문 바로가기

알고리즘

Boj 12852 c++ 1로 만들기 2

https://www.acmicpc.net/problem/12852

 

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

 

1로 만들기 #1463 을 이미 풀었기에 횟수를 구하는 방법에는 큰 문제가 없었다. 우선 1을 뺀 값을 기본값으로 설정해놓은 후, 

2 또는 3으로 나누어 떨어지는 경우에는 더 유리한 것으로 업데이트하는 방식이다. 하지만 최적해에 도달하기까지의 경로를 출력하는 방법은 익숙하지가 않아 이번 기회에 새로이 공부하게 되었다.

 

우선 문제 자체는 bottom-up dp로 풀이하였다.

 

dp에서 최종 해까지의 경로를 추적하는 방법은 'Parent' 와 같이 dp배열과 같은 크기의 배열을 이용하는 것이다.

각각의 인덱스는 이전 숫자를 가리킨다.

ex) 10 -> 9 -> 3 -> 1이라면

Parent[10] = 9       ->       Parent[9] = 3     ->     Parent[3] = 1 과 같은 방식이다.

 

while문을 통해 인덱스 값을 하나씩 출력하고, 부모가 0이되는 순간(1로 만들어진 순간) 에 종료하면 된다.

 

전체코드

#include<iostream>
#define Max 1000001
using namespace std;

int dp[Max];
int Parent[Max];

int main(){
    int n;
    cin >> n;

    dp[1] = 0;
    Parent[1] = 0;

    for(int i = 2; i <= n; i++) {
        dp[i] = dp[i-1] + 1;
        Parent[i] = i-1;


        if(i % 2 == 0 && dp[i] > dp[i/2]+1){
            dp[i] = dp[i/2] + 1;
            Parent[i] = i/2;
        }


        if(i % 3 == 0 && dp[i] > dp[i/3]+1){
            dp[i] = dp[i/3] + 1;
            Parent[i] = i/3;
        }

    }
    cout << dp[n] << "\n";
    cout << n << " ";
    while(Parent[n] != 0){
        cout << Parent[n] << " ";
        n = Parent[n];
    }
}

 

'알고리즘' 카테고리의 다른 글

Boj 10775 c++ 공항  (1) 2025.10.08
Boj 9252 c++ LCS 2  (0) 2025.10.01
Boj 11054 c++ 가장 긴 바이토닉 부분 수열  (0) 2025.09.28
Boj 배낭 문제 총집합  (0) 2025.09.20
Boj 2294 c++ 동전2  (0) 2025.09.17