코딩 문제

백준 1463 - 1로 만들기

토리쟁이 2023. 1. 14. 16:52

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

 

1463번: 1로 만들기

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

www.acmicpc.net

우르누ㅏㅓ룬아ㅜㄹ나ㅣㅜㄹ나ㅣㅜ

dp계속 못 푸는중,, 

코테볼라믄 이 dp를 뿌셔야되는데 내가 뿌셔지고 잇네..

 

이 문제는 진짜 단순히 어떤 수를 입력받아서 1로 만들어야되는데 1로 만들 때 필요한 연산의 최소 횟수를 구하는 문제이다. 연산은 1을 빼기, 2로 나누기, 3으로 나누기 이렇게 세 종류가 있다.

너무 문제가 단순해서 오히려 더 규칙을 찾아 알고리즘화하는 것이 어려운 것 같다.

그래서 다른 분의 풀이 코드를 참고했다.

https://seongonion.tistory.com/40

 

[백준] 1463번 1로 만들기 - 파이썬(Python)

문제 (링크) https://www.acmicpc.net/problem/1463 1463번: 1로 만들기 첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다. www.acmicpc.net 나의 풀이 n = int(input()) d = [0] * 1000001 for i in range(2, n+1

seongonion.tistory.com

이 포스팅을 참고 했는데 다른 포스팅들보다 더 자세하게 풀이 되어 있어서 이해하는데 많은 도움을 받았다.

 

 

그럼 정답 코드를 리뷰해보자.

풀이 코드)

x = int(input())
dp = [0] * (x+1)
dp[1] = 0

for i in range(2, x+1):
    dp[i] = dp[i-1] + 1

    if i%2 == 0:
        dp[i] = min(dp[i], dp[i//2] + 1)

    if i%3 == 0:
        dp[i] = min(dp[i], dp[i//3] + 1)

print(dp[x])

여기서 dp배열을 x+1의 크기만큼 선언 후 초기화했는데

dp에는 각 수를 1로 만들기 위해 걸리는 최소 연산횟수를 저장한다.

 

dp[1] = 1을 1로 만들기 위해 필요한 최소 연산 횟수 => 0

dp[2] = 2를 1로 만들기 위해 필요한 최소 연산 횟수 => 1 

dp[3] = 3을 1로 만들기 위해 필요한 최소 연산 횟수 => 1

 

처음에는 큰 수일 경우, 2보다는 3으로 나눠주어야 수가 더 작아지므로 3으로 나눠떨어지거나 3보다 1이 클 경우엔 1을 빼서 무조건 3으로 나누어주려고 했었다. 하지만, 이는 그냥 순간의 최선의 선택을 하는 그리디 알고리즘이고, 이 문제는 순간순간마다 최선의 선택을 한다고 해도 원하는 최종 결과값을 얻지 못한다.

 

즉, dp를 통해 모든 케이스(1을 빼거나/2로 나누거나/3으로 나누거나)를 다 해보아야한다는 소리이다.

 

dp[6]을 구하기 위해서는 3가지 경우가 존재한다.

설명의 편의성을 위해 

dp[4] = 2 , dp[5] = 3 을 구해놓고 설명하도록 하겠다.

 

1. 1을 빼는 연산을 했을 경우

1을 빼면 5가 된다. 그럼 5를 1로 만들기 위해 필요한 최소연산의 횟수 + 1을 해주면 된다.

+1을 하는 이유는 1을 빼는 연산을 했으니 그 연산에 대한 횟수를 올려주기 위함이다.

dp[6] = dp[5] + 1 ==> dp[i] = dp[i-1] + 1

dp[6] = 3 + 1 = 4

 

2. 2로 나누는 연산을 했을 경우

2로 나누면 3이 된다. 그럼 3을 1로 만들기 위해 필요한 최소연산의 횟수 +1을 해주면 된다.

+1을 하는 이유는 2로 나누는 연산을 했으니 그 연산에 대한 횟수를 올려주기 위함이다.

dp[6] = dp[3] + 1  ==> dp[i] = dp[i//2] + 1

dp[6] = 1 + 1 = 2

 

3. 3으로 나누는 연산을 했을 경우

3으로 나누면 2가 된다. 그럼 2를 1로 만들기 위해 필요한 최소연산의 횟수 +1을 해주면 된다.

+1을 하는 이유는 2로 나누는 연산을 했으니 그 연산에 대한 횟수를 올려주기 위함이다.

dp[6] = dp[2] + 1  ==> dp[i] = dp[i//3] + 1

dp[6] = 1 + 1 = 2

 

이렇게 dp[6]는 3가지 경우로 구할 수 있고, 이 문제에서는 가장 최소 횟수를 구하면 되므로 위 3가지 경우 중에서 가장 작은 값만 dp[6]에 저장해주면 된다. 따라서, dp[6] = 2가 된다.

이러한 알고리즘은 위의 풀이코드 반복문 안에 구현되어 있다.

 

마지막엔 숫자 x의 최소 연산 횟수만 출력하면 되므로, dp[x]를 출력해주면 된다.

'코딩 문제' 카테고리의 다른 글

백준 10844 - 쉬운 계단 수  (0) 2023.01.15
백준 2156 - 포도주 시식  (0) 2023.01.14
백준 2579 - 계단 오르기  (0) 2023.01.13
백준 1932 - 정수 삼각형  (0) 2023.01.12
백준 1149 - RGB거리  (0) 2023.01.12