본문 바로가기

알고리즘/백준

[BOJ 1038] 감소하는 수(다이나믹 프로그래밍, 수학 풀이)

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

 

1038번: 감소하는 수

음이 아닌 정수 X의 자릿수가 가장 큰 자릿수부터 작은 자릿수까지 감소한다면, 그 수를 감소하는 수라고 한다. 예를 들어, 321과 950은 감소하는 수지만, 322와 958은 아니다. N번째 감소하는 수를 출력하는 프로그램을 작성하시오. 0은 0번째 감소하는 수이고, 1은 1번째 감소하는 수이다. 만약 N번째 감소하는 수가 없다면 -1을 출력한다.

www.acmicpc.net



다이나믹 프로그래밍은 For문을 이용하거나, 재귀적으로 함수를 구성하는 것이 아니다. 문제를 나누어서 해결하는 것이다!

 

 

 

 

이 문제가 그러한 특징을 정확히 담고 있다.

 

 

 

 

새로운 감소하는 수를 찾으려면, 기존에 감수하는 수를 이용할 수 있다.

 

 

 

 

기존에 감소하는 수 마지막 자리 수보다 작은 새로운 수를 추가할 수 있으면 된다.

 

 

 

 

위의 알고리즘은 큐를 이용해서 쉽게 구현할 수 있다.

 

 

 

 

해설코드(C++).

 

#include <iostream>

#include <queue>

#include <vector>

 

using namespace std;

 

vector<long long> v;

queue<long long> q;

int N;

 

int main() {

    cin >> N;

    

    v.push_back(0);

    for(int i = 1; i <= 9; i++){

        q.push(i);

        v.push_back(i);

    }

    

    while(!q.empty()){

        long long item = q.front();

        for(int i = 0; i < item % 10; i++){

            q.push(item * 10 + i);

            v.push_back(item * 10 + i);

        }

        q.pop();

    }

    

    if(v.size() <= N)

        cout << -1 << endl;

    else

        cout << v[N] << endl;

    return 0;

}

 

 

 

 

위의 코드와 별개로 수학적 사고(?)로 접근해보자.



0 ~ 9에서 특정한 몇 개를 뽑아서 감소하는 수를 만든다고 생각해보자.


한 개를 뽑아서 조합을 만드는 경우, 10C1
두 개를 뽑아서 조합을 만드는 경우, 10C2
세 개를 뽑아서 조합을 만드는 경우, 10C3
...
열 개를 뽑아서 조합을 만드는 경우, 10C10



고등학교 때 배운 조합의 공식을 이용하면, 총 개수는 (2의 10승  - 1)을 이루게 된다.





비트 마스크를 이용해보자.





0000000000

0123456789




이진수의 각 자리수를 0 ~ 9로 매칭하고, 0은 뽑지 않은 상태, 1은 뽑은 상태라고 정의해보자.





그렇다면, 이진수의 조합으로 우리가 원하는 감소하는 수를 찾을 수 있다.





예를 들어,





0001000101

0123456789




 

위의 상태를 보고, 973으로 변환할수 있도록 값을 코드를 작성해야 한다. 십진수를 이진수로 변환하는 방법을 활용하면 된다.

 

 

 

 

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
#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
vector<long long> v;
int N;
 
int main() {
    cin >> N;
    for(long i = 1; i <= 1023; i++){
        long long val = i;
        long long temp = 0;
        for(long long j = 9; j >= 0; j--){
            if(val % 2 == 1)
                temp = temp * 10 + j;
            val /= 2;
        }
        
        v.push_back(temp);
    }
    
    sort(v.begin(), v.end());
    if(v.size() <= N)
        cout << -1 << endl;
    else
        cout << v[N] << endl;
    
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ 2169] 로봇 조종하기  (0) 2020.04.25
[BOJ 5582] 공통 부분 문자열  (0) 2020.04.22
[BOJ 9084] 동전  (1) 2020.04.19
[BOJ 11060] 점프 점프  (0) 2020.04.18
[BOJ 2302] 극장 좌석(접근법 및 시행착오 공유)  (0) 2020.04.18