[ 백준 ] 12919 / A와 B 2

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
140/228
post-thumbnail

# Appreciation

/*
 * Problem :: 12919 / A와 B 2
 *
 * Kind :: Backtracking
 *
 * Insight
 * - 문자열의 뒤에 A를 추가한다 <= 1번 연산
 *   문자열의 뒤에 B를 추가하고 뒤집는다 <= 2번 연산
 *
 * - S 로 T 를 만들기 위해 1글자씩 추가
 *   min(len(S)) = 1
 *   max(len(T)) = 50
 *   O(2^49) => 시간 초과
 *   + 흠...
 *
 * - 규칙이나 패턴이 있나?
 *   + 원래 문자열을 '-->' 라고 하자
 *     # -->AA // 1, 1
 *       BA<-- // 1, 2
 *       B<--A // 2, 1
 *       B-->B // 2, 2
 *       -> 흠...
 *
 * - S 로 T 를 만들지 말고, T 로 S 를 만들면 어떨까?
 *   + 가능한 T 의 경우를 다음과 같이 나눌 수 있다
 *     A-->A // A로 시작, A로 끝남
 *     A-->B // A로 시작, B로 끝남
 *     B-->A // B로 시작, A로 끝남
 *     B-->B // B로 시작, B로 끝남
 *     # 위의 경우를 만들 수 있는 그 이전의 문자열들을 생각해 본다면...
 *       A-->A <= A--> + 1번 연산
 *       A-->B <= 불가능
 *       B-->A <= A<-- + 2번 연산 OR B--> + 1번 연산
 *       B-->B <= B<-- + 2번 연산
 *
 * - B-->A 경우는 가능한 그 이전의 문자열이 2개 나오는데...
 *   연산량이 많아서 시간 초과 뜨지 않을까? (사실상 최악은 위와 똑같이 2^49 아냐?)
 *   + BX-->YA 라고 하자
 *     1번 연산을 되돌리면, BX-->Y
 *     Y가 A인 경우 B-->A 꼴로, 가능한 그 이전의 문자열이 2개 나온다
 *     Y가 B인 경우 B-->B 꼴로, 가능한 그 이전의 문자열이 1개 나온다
 *     2번 연산을 되돌리면, AY-->X
 *     X가 A인 경우 A-->A 꼴로, 가능한 그 이전의 문자열은 1개 나온다
 *     X가 B인 경우 A-->B 꼴로, 가능한 그 이전의 문자열은 없다
 *     # Y가 A인 경우와 X가 A일 때, 가능한 그 이전의 문자열의 총 개수가 3개로 가장 많다
 *       그러나 X가 A인 경우인 A-->A 는 그 이후로 가능한 문자열은 1개 밖에 없다
 *       (A로만 이루어진 꼴)
 *       -> 즉,
 *          1 - B-->A (T)
 *                |\___
 *                |    \
 *          2 - B-->A, A-->A // len(T)-1 의 길이를 가진 T 를 만들 수 있는 문자열 S
 *                |\___   \___
 *                |    \      \
 *          3 - B-->A, A-->A, A-->A // len(T)-2 의 길이리르 가진 T를 만들 수 있는 문자열 S
 *          ...
 *
 * - O(len(S)) - 문자열 비교 연산
 *   O(1+2+3+...+(len(T)-len(S)) - T 를 만들 수 있는 S 의 개수 => O(N^2)
 *   + 문자열 비교 연산은 O(max(len(S)) <= O(N) = O(50) 로
 *     T 가 주어졌을 때 가능한 S 의 개수를 <= O(N^2) = O(50^2) 로
 *     크게크게 잡아도
 *     O(50^3) 으로 시간 제한 내에 충분히 풀 수 있다!
 */

# Code

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

#include <iostream>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
string pop(string s);
string turn(string s);
bool isPossible(const string &S, string T);


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

    // Set up : Input
    string S; cin >> S;
    string T; cin >> T;

    // Process
    // Control : Output
    cout << ((isPossible(S, T)) ? 1 : 0 ) << endl;
}

// Helper Functions
string pop(string s)
/* 주어진 문자열에서 마지막 글자를 지운 문자열을 반환 */
{
    s.pop_back();
    return s;
}

string turn(string s)
/* 주어진 문자열을 뒤집은 문자열을 반환 */
{
    reverse(s.begin(), s.end());
    return s;
}

bool isPossible(const string &S, string T)
/* S 로부터 연산을 통해 T 를 만들 수 있으면 true 를 반환, 그 외 false 를 반환 */
{
    if (S == T) /* S 와 T 가 같으면 */
        return true; /* S 로부터 T 를 만들 수 있음 */

    if (T.length() >= 2) {
        char f = T.front(); /* T 맨 앞 글자 */
        char b = T.back(); /* T 맨 뒷 글자 */

        /* A-->A 꼴이면 */
        if (f == 'A' && b == 'A')
            /* 1번 연산을 되돌린 A--> 꼴로 검사를 계속 진행 */
            return isPossible(S, pop(T));

        /* A-->B 꼴이면 */
        if (f == 'A' && b == 'B')
            /* 불가능 */
            return false;

        /* B-->A 꼴이면 */
        if (f == 'B' && b == 'A') /* B-->A 꼴이면 */
            /* 1번 연산을 되돌린 B--> 꼴과
             * 2번 연산을 되돌린 A<-- 꼴로 검사를 계속 진행 */
            return isPossible(S, pop(T)) || isPossible(S, pop(turn(T)));

        /* B-->B 꼴이면 */
        if (f == 'B' && b == 'B')
            /* 2번 연산을 되돌린 B<-- 꼴로 검사를 계속 진행 */
            return isPossible(S, pop(turn(T)));
    }

    return false;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글