백준

[220831] 백준풀기 (1463)

2022. 8. 31. 16:13

 

- 1463: 1로 만들기 (성공, 다시 풀어보기)

 

     첫번째 시도: X가 3으로 나누어 떨어질 때, X가 2로 나누어 떨어질 때, 그 외 경우는 1을 빼도록 나눔

      => 9, 27과 같이 계산을 적게 할 수 있는 경우를 고려하지 못함

 

     두번째 시도: (X-1)%3 == 0형태를 사용해 작은 숫자가 3이나 2로 나누어 떨어진다면 이도 고려하도록 했다.

                          또 X-1 어떤 수의 제곱수라면 그 수로 만들어주는 것이 가장 빠르게 계산하는 방법이라 생각해

                          해당 수가 제곱수인지 판별하는 함수도 만들었다.

      => 이 코드도 가장 적게 계산할 수 있는 경우를 고려하지 못했다.

 

 

     이 문제를 해결하기 위해서는 DP(다이나믹 프로그래밍)을 사용해야 했다.

     모든 각각의 숫자가 계산되는 횟수를 다 구해 저장해둔 후 그 중 최솟값을 찾아 출력하는 방식을 사용한 것이다.

     여기서 시간복잡도를 줄이기 위해 vector와 min함수 등이 필요했다.

     <dp[2] 라면 2라는 숫자에서 1이 될때까지 필요한 계산 횟수가 저장된 공간을 의미>

     < 2와 3이 기준이기 때문에 X에서 1만 빼줘도 2 또는 3으로 나누어 떨어지는 수에 접근할 수 있게된다.>

 

     1. n+1 크기의 dp 벡터를 선언한다.

        dp[1]엔 0을 넣어주고, dp[2], dp[3] 엔 1, dp[4] 엔 2를 넣어준다. 

        (위처럼 숫자가 작은 경우는 미리 계산해 넣어주었다.)

        이후 for문으로 5부터 n까지 반복하며 dp벡터에 계산값을 저장한다.

 

     2. if문을 사용해 4가지 종류로 경우의 수를 나눈다. 

         - X가 2와 3 어떤 수로도 나누어 떨어지지 않는경우

            => X에서 1을 빼주는 계산만 해주면 dp[i-1]번 계산하면 되므로 dp[i]에 dp[i-1]+1을 저장한다.

         - X가 2로 나누어 떨어지는 경우

            => dp[i/2] + 1 ~ dp[i-1] + 1 까지의 수 중 min함수를 통해 최소값을 구해 dp[i]에 저장한다.

         - X가 3으로 나누어 떨어지는 경우

            => dp[i/3] + 1 ~ dp[i-1] + 1 까지의 수 중 min함수를 통해 최소값을 구해 dp[i]에 저장한다.

         - X가 2와 3 모두로 나누어 떨어지는경우

            => dp[i/2] + 1 ~ dp[i/3] + 1 까지의 수 중 min함수를 통해 최소값을 구해 dp[i]에 저장한다.

      (여기서 +1을 해주는 이유는 1만 빼주어도 2또는 3으로 나누어 떨어지게 되기 때문에 +1을 해줌으로써

        1을 빼주는 계산을 했다고 치고, dp[i-1]까지의 계산을 고려하기 위함이다.)

 

     3. for 반복문이 끝났다면 dp[n], 최종으로 계산된 횟수값을 출력한다.

      

 

 

'백준' 카테고리의 다른 글

백준 27866번: 문자와 문자열, c++  (0) 2023.09.13
백준 2611: 오타맨 고창영  (0) 2023.08.11
[220830] 백준풀기 (11658)  (0) 2022.08.31
[220828] 백준풀기 (2445)  (0) 2022.08.28
[220827] 백준풀기 (1453)  (0) 2022.08.28