Today
Total
Archives
05-10 01:18
관리 메뉴

tony9402

[백준 1463] 1로 만들기 본문

알고리즘/Baekjoon Online Judge

[백준 1463] 1로 만들기

ssu_gongdoli 2019. 1. 23. 02:10
반응형

문제 : 1로 만들기

문제 유형 : 다이나믹 프로그래밍



이 문제의 핵심은 입력 받은 수를 최소 횟수로 1로 만드는 것이다.


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

2. X가 2로 나누어 떨어지면, 2로 나눈다.

3. X에서 1을 뺸다.


위 세가지를 이용해서 1로 만들어야 하는데 이를 어떻게 할까? 다이나믹 프로그래밍 문제를 풀 땐 너무 복잡하게 생각하면 오히려 안풀린다.


다이나믹 프로그래밍 문제를 풀기 위한 방법은 탑다운 방식과 바텀업 방식이 있다. 나도 공부하는 입장이니 두 가지 방법으로 설명하겠다.




1. 탑다운(Top-down) 방식


현재 수를 X라 하자. X가 3으로 나눠떨어진다면 X/3을 만드는 횟수는 X 만든 횟수에 한번더 연산을 한 것이기 때문에 X를 만든 횟수에 +1을 해주면 된다.

이와 마찬가지로 X가 2로 나눠 떨어진다면 X/2을 만드는 횟수는 X를 만드는 횟수에 +1을 하면 된다. 연산 3번도 마찬가지로 X를 만든 횟수에 +1한건 X-1을 만드는 횟수이다.


여기서 조심해야할껀 횟수의 최솟값을 만드는 것이기 때문에 +1 값이 그 다음 수를 만드는 수보다 작으면 갱신하게 만들면 된다.




탑다운 방식을 이용할 땐 dp배열을 10^6보다 큰 수로 채워놓으면 된다. (또는 값이 0일땐 그냥 대입해도 된다.)


시간복잡도 : O(N)


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
#include<iostream>
#include<algorithm>
 
using namespace std;
typedef long long ll;
 
ll dp[1000001];
const ll inf = 2000000;
 
int main()
{
    ll n;
    fill(dp, dp + 1000000, inf);
    cin >> n;
    dp[n] = 0;
    for (int i = n; i > 0; i--)
    {
        if (dp[i] == inf)continue;
        if (i % 3 == 0)dp[i / 3= min(dp[i / 3], dp[i] + 1);
        if (i % 2 == 0)dp[i / 2= min(dp[i / 2], dp[i] + 1);
        if (i >= 2)dp[i - 1= min(dp[i - 1], dp[i] + 1);
    }
    cout << dp[1];
    return 0;
}

cs




2. 바텀업(Buttom-up) 방식


탑다운과 거의 똑같은 풀이이다. 탑다운에서는 나눠 떨어지는지 확인을 했다면 바텀업에서는 그냥 곱하고 더하면 된다.


메모리를 좀 적게 써야한다 하면 곱했을때 구해야하는 값보다 크지 않을때만 넣어주면 된다. 하지만 이 문제는 10^6밖에 안되니 그냥 배열을 어느정도 크게 해놓고 계산을 하면 된다.



 - 메모리 생각해서 간단한 조건을 줬을 때 -시간복잡도 : O(N)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
 
#define min(x,y) (x) < (y) && (x) != 0 && (y) != 0 ? (x) : (y)
 
int DP[1000001= { 0 };
 
int main()
{
    int n;
    scanf("%d"&n);
    for (int i = 1; i <= n;i++) {
        if (i + 1 <= n)DP[i + 1= min(DP[i + 1], DP[i] + 1);
        if (i * 2 <= n) {
            DP[i * 2= min(DP[i * 2],DP[i] + 1);
        }
        if (i * 3 <= n) {
            DP[i * 3= min(DP[i * 3],DP[i] + 1);
        }
    }
    printf("%d", DP[n]);
    return 0;
}

cs



 - 메모리 생각안하고 간단히 소스 코드 짰을 때 -시간복잡도 : O(N)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
 
#define min(x,y) (x) < (y) && (x) != 0 && (y) != 0 ? (x) : (y)
 
int DP[3000001= { 0 };
 
int main()
{
    int n;
    scanf("%d"&n);
    for (int i = 1; i <= n;i++) {
        DP[i + 1= min(DP[i + 1], DP[i] + 1);
        DP[i * 2= min(DP[i * 2],DP[i] + 1);
        DP[i * 3= min(DP[i * 3],DP[i] + 1);
    }
    printf("%d", DP[n]);
    return 0;
}

cs


반응형

'알고리즘 > Baekjoon Online Judge' 카테고리의 다른 글

[백준 2448] 별 찍기-11  (3) 2019.03.15
[백준 9657] 돌 게임 3  (0) 2019.01.25
[백준 9461] 파도반 수열  (0) 2019.01.23
[백준 15991] 1,2,3 더하기 6  (0) 2018.11.24
[백준 15990] 1,2,3 더하기 5  (0) 2018.11.22
Comments