개발/알고리즘

백준 1038) 감소하는 수 골드 5 - 백트래킹

차가운콩 2024. 12. 10. 09:42

 

풀이: 이 문제는 백트래킹을 사용하면 된다고 한다 하지만 이 문제를 읽고 구상을 해보면 뭔가 BFS의 느낌으로 구현하여야 하는데 백트래킹은 DFS의 원리와 비슷하여 어떻게 백트래킹을 사용할 것 인가가 중요한 것 같다. 

 

아래는 간단한 예시이다 보면 0 1 2 4 5 6 7 8 9인 1의 자리를 먼저 탐색하고 -> 10 20 21 ... 그 다음 자릿수로 넘어가야한다

 0 1 2 3 4  5 6 7 8 9 

    0 0 0 0  ...            

       1 1 1                 

          2 2                 

             3                 

 

이 문제를 푸는 핵심 방법은 현재 자릿수에서 가장 큰 감소하는 수를 찾았다면 자릿수를 하나 더 늘려서 다시 탐색하는 것

 

1의 자릿에서는 9  ->  2의 자리에서는 98 -> 3의 자리에서는 987 -> 4의 자리에서는 9876이 이 수들의 규칙을 보면 

 

떠오르는 것이 있을 것이다. 앞은 9로 시작하고 뒤는 10 - 수의 자릿수로 끝나야 한다는 것!  -> 그럼 코드로 짜보자 

 

숫자를 dp라는 이름의 vector에 저장하면 dp[0]이 무조건 9이고 dp의 마지막 값이 10 -  sizes와 같아야 한다는 조건이다

 

여기서 10 - sizes는 여기서 나올 수 있는 최대값이 9876543210이니까 10자리를 넘어가는 경우는 있을 수 없다. 

 

아래 코드에서는 가지치기를 하지 않았는데 안해도 통과해서 가지치기는 본인 마음대로 하면 될 것 같다.

 

#include <iostream>
#include <vector>
using namespace std;
long long n;
long long ct = -1;
int sizes = 0;
bool is_found = false;


void func(vector<int> dp) {
    if (is_found) return;

    if (!dp.empty() && dp.size() == sizes) {
        ct++;
        if (ct == n) {
            is_found = true;
            for (auto a: dp) {
                cout << a;
            }
            return;
        }
    }


    if (dp.empty() || (dp.size() == sizes && !dp.empty() && dp[0] == 9 && dp.back() == 10 - sizes)) {
        sizes++;

        if (sizes == 11) {
            cout << -1;
            is_found = 0;
            return;
        }

        dp.clear();
        for (int i = sizes-1; i <= 9; i++) {
            dp.push_back(i);
            func(dp);
            dp.pop_back();
        }
        return;
    }

    int back = dp.back();
    if (!dp.empty() && dp.size() < sizes) {
        for (int i = 0; i < back; i++) {
            dp.push_back(i);
            func(dp);
            dp.pop_back();
        }
    }
}

int main() {
    cin >> n;
    if (!n) {
        cout << 0;
        return 0;
    }
    vector<int> dp;
    func(dp);
}