1로 만들기

Program Lang./Algorithm 2017. 10. 26. 19:36

1. 소스 코드

백준 https://www.acmicpc.net/problem/1463 문제 정리.

이 문제를 처음 접하는 순간 아무 생각이 들지 않았다. 나는 왜 이리 멍청할까 정도만 생각이 들지

모든 문제를 해결하기 위해서 먼저 완전탐색부터 고민하면서 속도 개선을 위해서 하나 하나 개선해 가는 식으로 여기에 정리한다. 참고로 여러 사람들이 해 놓은 코드를 참조하였다.

아래 코드는 완전 탐색으로 구현한 내용이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
 
unsigned int min = 0xFFFFFFFF;
 
void f(int n, unsigned int d)
{
    if(n == 1)
    {
        if(min > d)
        {
            min = d;
        }
 
        return;
    }
 
    f(n-1, d+1);
 
    if(n%2 == 0)
    {
        f(n/2, d+1);
    }
     
    if(n%3 == 0)
    {
        f(n/3, d+1);
    }
}
 
int main()
{
    int n;
    std::cin >> n;
 
    f(n, 0);
 
    std::cout << min << std::endl;
    return 0;
}


2. DP 코드

dp[n] = f(n-1) + 1로 완전탐색 루틴에서 가장 왼쪽 노드의 값에서 차례되로 dp[n]값을 구하고 f(n/2) 또는 f(n/3)에서 그 값이 더 작으면 dp[n]을 update하는 식으로 처리하면서 최종값을 얻는다.
결론적으로 위 완전 탐색에서 f함수 두번째 매개변수 처리를 dp배열로 어떻게 처리하느냐가 관건으로 보인다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
 
int dp[10000000 + 1];
 
int f(int n)
{
    if(n == 1)
    {
        return 0;
    }
 
    dp[n] = f(n-1) + 1;
 
    if(n%2 == 0)
    {
        int d = f(n/2) + 1;
        if(dp[n] > d)
        {
            dp[n] = d;
        }
    }
 
    if(n%3 == 0)
    {
        int d = f(n/3) + 1;
        if(dp[n] > d)
        {
            dp[n] = d;
        }
    }
 
    return dp[n];
}
 
int main()
{
    int n;
    std::cin >> n;
 
    std::cout << f(n) << std::endl;
    return 0;
}


결론적으로 재귀함수 호출을 모두 제거하면 아래와 같은 코드로 완성할 수 있다.
위의 재귀함수 호출 코드를 하나하나 따라가 보면 결국 재귀함수 호출 내에서 DP값이 모두 구해져 있어서
DP값으로 재귀함수 변환값은 대체된다. 이를 통해서 재귀호출 구문은 아래처럼 모두 없앨 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
 
int dp[10000000 + 1];
 
int main()
{
    int n;
    std::cin >> n;
 
    dp[0] = 0;
    dp[1] = 0;
    dp[2] = 1;
    dp[3] = 1;
 
    for(int i = 4; i <= n; i++)
    {
        int d1 = 0x1FFFFFFF, d2 = 0x1FFFFFFF, d3 = 0x1FFFFFFF;
 
        d1 = dp[i-1];
         
        if(i%2 == 0)
        {
            d2 = dp[i/2];
        }
 
        if(i%3 == 0)
        {
            d3 = dp[i/3];
        }
 
        dp[i] = std::min(std::min(d1, d2), d3) + 1;
 
        //std::printf("%d %d %d %d %d \n", i, d1, d2, d3, dp[i]);
    }
 
    std::cout << dp[n] << std::endl;
    return 0;
}


'Program Lang. > Algorithm' 카테고리의 다른 글

최소 신장 트리 - 프림(Prim) 알고리즘  (0) 2017.11.20
위상정렬 (Topological Sort) - Indegree  (0) 2017.11.06
계단오르기  (0) 2017.10.25
숫자삼각형 문제풀이  (0) 2017.10.25
RGB 거리  (0) 2017.10.22
: