[editorial] 2008년 서울대회 인터넷 예선 B번 6174

  • JongMan
    JongMan

    Problem Statement
    어떤 4자리 숫자가 주어질 때, 이 수의 자릿수들을 재배열해서 만들 수 있는 가장 큰 수와 가장 작은 수의 차를 얻는 함수를 Kaprekar 변환이라고 합니다. 놀랍게도, 1111 이나 2222 같은 수를 제외하면 모든 4자리 수에 반복해서 Kaprekar 변환을 적용하면 결과적으로 6174 를 얻게 되는데, 몇번이나 이 변환을 해야 할까요?
    Analysis
    B번답게 비교적 쉬운 문제입니다. 'ㅅ' 일단, 어떤 4자리 수가 주어졌을 때, 자리수를 재배열해서 얻을 수 있는 가장 큰 수와 작은 수는 자릿수들을 각각 오름차순과 내림차순으로 정렬하면 얻을 수 있단 것을 쉽게 알 수 있죠. 그러면, Kaprekar 변환을 함수로 작성할 수 있고, 남은 것은 다음과 같이 n 이 수렴할 때까지 함수를 반복 호출하는 것 뿐입니다.

    cin >> n;
    while(n != "6174")
    {
            n = next(n);
            ++steps;
    }
    cout << steps << endl;
    

    모든 숫자는 최대 10000번의 변환 안에 6174 로 수렴할 것이고 (실제로는 모든 숫자가 7번의 변환 안에 수렴합니다), 테스트 케이스는 20개밖에 안 되니 이렇게 간단하게 풀어도 시간 안에 충분히 들어갈 수 있겠지요. ^^
    Source Code
    다음은 이 문제의 간략한 구현입니다. n 을 표현하는 데 숫자를 쓰지 않고, 문자열을 씀으로써 Kaprekar 변환 함수를 짧게 할 수 있었습니다. ^^

    #include <string>
    #include <algorithm>
    using namespace std;
    string next(string p)
    {
            string mini = p, maxi = p;
            sort(mini.begin(), mini.end());
            sort(maxi.begin(), maxi.end(), greater());
            char buf[16];
            sprintf(buf, "%04d", atoi(maxi.c_str()) - atoi(mini.c_str()));
            return buf;
    }
    int main()
    {
            int cases;
            cin >> cases;
            while(cases--)
            {
                    int steps = 0;
                    string n;
                    cin >> n;
                    while(n != "6174")
                    {
                            n = next(n);
                            ++steps;
                    }
                    cout << steps << endl;
            }
    }
    
    [이 글은 과거 홈페이지에서 이전된 글입니다. 원문보기]

    16년 전
2개의 댓글이 있습니다.
  • 하루
    하루

    최대 7번의 변환만 거치면 된답니다 ^^;


    16년 전 link
  • JongMan
    JongMan

    오, 그렇군요. 확인해 보고 올릴걸. 뭐 upper bound 는 확실하니까요. ^^;


    16년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.