[BOJ][C++] 백준 1463번 1로 만들기

Updated:

1463번 1로 만들기

1. 문제 정보

백준 온라인 저지 [1463번 1로 만들기] 문제의 링크입니다.

문제

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

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

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

입력

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.


예제 입력1

2

예제 출력1

1

예제 입력2

10

예제 출력2

3

시간 / 메모리 제한

2초 / 128MB

힌트

10의 경우에 10 -> 9 -> 3 -> 1 로 3번 만에 만들 수 있다.


2. 생각

  1. 세 가지 방법 중 수를 가장 작게 만드는 방법은 큰 수로 나누는 방법입니다. 따라서 3으로 나누고 나누어 지지 않는다면 2로 나누고 2로도 나누어지지 않는다면 1을 빼는 방법이 수를 빠르게 작게 만들 수 있습니다.

그러나 이 방법으로는 주어진 문제를 풀 수 없습니다. 그 반례는 힌트로 주어진 10의 경우입니다. 10의 경우에는 10 -> 9 -> 3 -> 1로 1을 먼저 빼는 방법이 최소 횟수입니다.

dp[i] 횟수 방법
dp[1] 0번 1이므로 0번 연산
dp[2] 1번 1빼기 1번 or 2로 나누기
dp[3] 1번 1빼기 2번 or 3으로 나누기
dp[4] 2번 1빼기 3번 or 1뺴고 3으로 나누기 or 2로 2번 나누기
dp[5] 3번 1빼기 4번 or 1뺴고 1빼고 3으로 나누기 or 1빼고 2로 2번 나누기
dp[6] 2번 1빼기 5번 or 1빼기 3번 후 3으로 나누기 or 1빼기 2번 후 2로 2번 나누기 or 3으로 2번 나누기
dp[7] 3번 1빼고 3으로 두 번 나누기 (dp[6] 활용)
  1. Bottom-up 방식의 다이나믹 프로그래밍 방식을 사용하겠습니다.
    dp[i]를 구할 때 dp[i-1]의 값을 활용할 것인데, dp[i-1]의 값을 최적의 해라고 생각하여 dp[i-1]의 값을 활용합니다.

  2. dp[i]의 값을 구할 때에 3가지의 경우가 있습니다.

    1) 1을 빼는 경우가 최적일 경우 :

    1을 빼므로 dp[i-1]의 값(연산 횟수)에 1을 빼는 연산 1번을 추가해줍니다.

    -> dp[i-1] + 1

    2) 2로 나누는 경우가 최적일 경우 :

    2로 나누므로 dp[i/2]의 값(연산 횟수에) 2를 나누는 연산 1번을 추가해줍니다.

    -> dp[i/2] + 1

    3) 3으로 나누는 경우가 최적일 경우 :

    3으로 나누므로 dp[i/3]의 값(연산 횟수에) 3을 나누는 연산 1번을 추가합니다.

    -> dp[i/3] + 1


3. 소스코드 (C++)


터미널의 입출력 화면 예제1

1463_1

터미널의 입출력 화면 예제2

1463_2 1463_3