[타 사이트 문제]주어진 문자열을 팰린드롬으로 나누는 문제입니다. 좀 봐주세요ㅠㅠ

  • robustFlame
    robustFlame

    타 사이트 문제입니다. (출처)

    • 문제를 요약하자면 다음과 같습니다.
      주어진 문자열을 최소한의 팰린드롬으로 자르는 문제입니다.
      (팰린드롬(palindrome)이란 앞에서부터 읽으나 뒤에서부터 읽으나 같은 단어를 말한다.ex) a, aba 등)
      예를 들어 anavolimilana는 ana, v, o, limil, ana이렇게 5개로 자를 수 있습니다.(더 적은 수로는 나누지 못합니다.)

    • 제가 이 문제를 푼(틀렸지만) 방식은 다음과 같습니다.

    일단 주어진 문자열에서 팰린드롬이 될 수 있는 모든 부분문자열을 찾아서 palindromeInfo라는 이중벡터에 그 정보를 넣습니다. (주어진 문자열에 i번째 문자에서 시작해서 j번째 문자로 끝나는 부분문자열이 팰린드롬이면 palindromeInfo[i]에 j를 push_back합니다)
    예를 들어서 anavolimilana라는 문자열이 주어지면
    palindromInfo[0] = { 0, 2 }; // a, ana
    palindromInfo[1] = { 1 }; // n
    palindromInfo[2] = { 2 }; // a
    ...
    palindromInfo[5] = { 5, 9 }; // l, limil
    ...
    palindromInfo[10] = { 10, 12 }; // a, ana
    와 같은 정보를 구성합니다.

    그리고 나서 palindromInfo의 값들을 가지고 완전탐색을 합니다. 완전탐색 방식은 문자열의 인덱스k를 주면 k번째에서 시작해서 팰린드롬을 만들 수 있는 모든 경우(이 정보는 앞에서 palindromeInfo에서 다 구해 놓음)에 대해서 그 다음 문자의 인덱스로 재귀호출을 합니다. 결과들 중 최소값을 취하고 1을 더하면 됩니다. 주어진 인덱스에 대해 항상 최소의 값을 반환하므로 최적 부분 구조(?)가 성립합니다. 이에 대한 구현은 아래 minPalindrome()함수입니다.(글로 표현하는게 참 어렵네요;;)

    #include <iostream>
    #include <vector>
    #include <string>
    #include <limits>
    #include <cstring>
    using namespace std;
    
    const int INF = numeric_limits<int>::max();
    
    string TestString;  // 입력 문자열
    int LengthOfString; // 입력 문자열의 길이
    int Cache[2000];    // 캐시 메모리
    
    // 문자열의 처음과 끝의 인덱스가 주어지면 팰린드롬인지 아닌지 체크한다.
    bool isPalindrome(int first, int last) {    
        int half = (last - first + 1) / 2;
        for (int i = 0; i < half; i++) {
            if (TestString[first + i] != TestString[last - i])
                return false;
        }
        return true;
    }
    // start번 문자에서 시작해서 남은 문자열들을 팰린드롬으로 나눌 수 있는 최솟값을 반환한다. 
    int minPalindrome(const vector<vector<int> >& palindromeInfo, int start) {
        // 기저사례 : 문자열 인덱스를 벗어난 경우
        if (start == LengthOfString)    
            return 0;
    
        int& ret = Cache[start];    
        if (ret != -1) return ret;  
        const vector<int>& currentInfo(palindromeInfo[start]);
        ret = INF;
        // 다음 인덱스가 될 수 있는 경우들에 대해서 최적의 값을 구한다.
        for (int i = 0; i < currentInfo.size(); i++) {   
            ret = 1 + min(ret, minPalindrome(palindromeInfo, currentInfo[i] + 1));
        }
        return ret;
    }
    
    int main() {
        memset(Cache, -1, sizeof(Cache));
        cin >> TestString;
        LengthOfString = TestString.size();
        vector<vector<int> > palindromeInfo(LengthOfString);
        // palindromeInfo 구성 하기
        for (int i = 0; i < LengthOfString; i++) {
            for (int j = i; j < LengthOfString; j++) {
                if (isPalindrome(i, j))
                    palindromeInfo[i].push_back(j);
            }
        }   
        // 0번째 문자로 시작 
        cout << minPalindrome(palindromeInfo, 0);
    
    }
    

    사실 이런 질문은 하지 말라고 했는데 제가 생각한 예시들 모두 맞는데 틀렸다고 하니까 멍~하네요ㅠㅠ
    제가 문제를 잘못 이해한 건가요? 알고리즘적으로도 맞는거 같은데 ㅠㅠ 고수님들 도와주십쇼.
    당연히 맞는거라 생각했는데 원인도 모르고 틀리고 있으니까 다른 문제 풀기가 싫어지네요


    8년 전
2개의 댓글이 있습니다.
  • kriii
    kriii

    minPalindrome에서 ret을 갱신하는 부분이 이상하네요


    8년 전 link
  • robustFlame
    robustFlame

    ㄴ해결했습니다! 감사합니다.
    그 부분에 대해서 생각을 했었는데 불필요한 연산이 있지만 어차피 최솟값을 구한다 생각하고 넘겼는데 자세히 살펴보니까 문제가 있었네요 ㅠㅠ 감사합니다. 이래서 코딩을 명확하게 해야 하나 봅니다.


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