12852번: 1로 만들기 2
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 자연수 N이 주어진다.
www.acmicpc.net
문제
정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지이다.
- X가 3으로 나누어 떨어지면, 3으로 나눈다.
- X가 2로 나누어 떨어지면, 2로 나눈다.
- 1을 뺀다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.
입력
첫째 줄에 1보다 크거나 같고, 10^6보다 작거나 같은 자연수 N이 주어진다.
출력
첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.
둘째 줄에는 N을 1로 만드는 방법에 포함되어 있는 수를 공백으로 구분해서 순서대로 출력한다. 정답이 여러 가지인 경우에는 아무거나 출력한다.
예제 입력 1 복사
2
예제 출력 1 복사
1
2 1
예제 입력 2 복사
10
예제 출력 2 복사
3
10 9 3 1
문제 설명
입력을 받아 3이나 2로 나누거나 1을 빼서 1로 만들 수 있는 경우의 수 중, 가장 짧은 경우의 수를 출력하는 문제
이 문제의 입력값이 백만보다 작거나 같은 수 이므로 O(N) 안에 해결해야 한다.
그리하여 다이나믹 프로그래밍 중 Bottom-up 방식을 사용해 문제를 해결하였다.
문제 풀이
이차원 배열 dp를 선언
각 배열에는 각 수에서 1까지 도달할 수 있는 경우의 수 중 가장 짧은 경우의 수를 저장할 것이다.
그리고 i가 3으로 나누어 떨어지거나 2로 나누어 떨어지는 경우 각 dp[i//3], dp[i//2]와 비교하여 길이가 더 짧은 경우를 저장한다.
그 결과로 생성된 dp의 index N은 N을 1로 만드는 경우의 수 중 가장 짧은 경우를 저장하게 된다.
하지만 이 경우 1부터 N까지 출력이 되므로 역순으로 출력을 해 주면 된다.
코드
N = int(input())
dp = [[] for _ in range(10**6+1)]
dp[1] = [1]
for i in range(2,N+1):
dp[i] = [i for i in dp[i-1]]
if i % 3 == 0:
dp[i] = [i for i in min(dp[i],dp[i//3],key=lambda x : len(x))]
if i % 2 == 0:
dp[i] = [i for i in min(dp[i],dp[i//2],key=lambda x : len(x))]
dp[i].append(i)
print(len(dp[N])-1)
print(*reversed(dp[N]))
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 11758 CCW (Python) (0) | 2023.02.18 |
---|---|
[백준] 15486 퇴사 2 (Python) (0) | 2023.02.18 |
[백준] 11055 가장 큰 증가 부분 수열 (Python) (0) | 2023.02.18 |
[백준] 10844 쉬운 계단 수 (Python) (0) | 2023.02.16 |
[백준] 2156 포도주 시식 (Python) (0) | 2023.02.16 |