[ 백준 ] 2661 / 좋은수열

金弘均·2021년 9월 14일
0

Baekjoon Online Judge

목록 보기
25/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2661 / 좋은수열
 *
 * Kind :: DFS + Backtracking
 *
 * Insight
 * - 길이가 N 미만인 나쁜 수열은 어떤 수들을 추가하더라도 길이가 N 인 나쁜 수열이 된다
 *   길이가 N 인 좋은 수열은 길이 N 미만의 좋은 수열로 이루어져있다
 *   + 길이가 A 인 좋은 수열이 있다면 수를 추가해주면서
 *     길이가 A+1, A+2, ..., N 인 좋은 수열을 찾아주자
 *
 * - 그런데 문제는 길이가 N 인 좋은 수열 중 가장 작은 수를 나타내는 수열을 찾아야 한다
 *   추가해주는 수의 순서를 1, 2, 3 으로 하여 가장 작은 수부터 찾아낼 수 있게끔 하자
 *   + 하지만 현재 길이가 A 인 가장 작은 수의 좋은 수열로부터
 *     길이가 N 인 좋은 수열을 만들 수 있지 않을 수도 있다!
 *     # 1213121, 2123212 모두 길이가 7 인 좋은 수열이다
 *       길이가 8 인 좋은 수열을 만들때, 1213121 은 뒤에 어떤 수가 오더라도 나쁜 수열이 돼버린다
 *       즉, N 미만 모든 길이의 좋은 수열을 찾아야 한다
 *       -> 실제로 현재 좋은 수열에서 수를 추가할 때
 *          추가되는 수는 수열의 마지막 수와 달라야 하기 때문에
 *          모두 탐색한다면 O(2^80) 이다
 *          => 그러나 나쁜 수열은 어떤 수들을 추가해도 나쁜 수열이므로
 *             Backtracking 을 적용해서 최적화를 해주자!
 *
 * Point
 * - 사실 1 <= N <= 80 의 범위에서
 *   길이 N 인 좋은 수열이 무조건 하나 이상 존재하나? 싶었는데
 *   실제로 구해보니 존재하더라
 *   + 왜지...?
 *     그러나 알아보기엔 너무많은 정수론적 지식이 들어갈 것 같아
 *     증명은 스킵한다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int N;
string A;

// Set up : Functions Declaration
bool isGood(const string& s);
bool f(string s);


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    cin >> N;

    // Process
    bool isPossible = f("");

    // Control : Output
    cout << ((isPossible) ? A : "-1") << endl;
}

// Helper Functions
bool isGood(const string& s)
/* 문자열 s 를 수열로 보고
 * 수열의 마지막 수가 포함된 임의의 길이의 인접한 두 개의 부분 수열을 검사하여
 * 좋은 수열이면 true 를 반환, 그 외 false 를 반환 */
{
    int len = s.length();
    for (int i=1; i<=len/2; i++) {
        string a1 = s.substr(len-2*i, i);
        string a2 = s.substr(len-i, i);
        if (a1 == a2) return false;
    } return true;
}

bool f(string s)
/* 문자열 s 를 수열로 보고
 * 길이가 N 인 가장 작은 수의 좋은 수열을 찾으면 true 를 반환, 그 외 false 를 반환 */
{
    if (s.length() == N) { /* 길이가 N 인 가장 작은 수의 좋은 수열을 찾았다면 */
        A = s; /* 길이 N 인 좋은 수열을 전역변수 A 에 저장 */
        return true;
    }
    else {
        for (char c : {'1', '2', '3'}) {
            /* c 라는 수를 추가한 새로운 수열이 좋은 수열이며
             * 이 수열을 통해 길이가 N 인 가장 작은 수의 좋은 수열을 만들 수 있다면
             * 현재 함수의 실행을 종료시키고 true 를 반환 */
            if (isGood(s+c) && f(s+c)) {
                return true;
            }
        }
    }

    /* s 로는 길이가 N 인 가장 작은 좋은 수열을 만들 수 없음 */
    return false;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글