알고리즘/BOJ

백준 15881번 Pen Pineapple Apple Pen

꾸준함. 2018. 7. 3. 01:35

문제 링크입니다: https://www.acmicpc.net/problem/15881


겉보기에는 쉬운 문제 같지만 사실은 주어진 문자열에서 "pPAp" 형태를 띄는 부분 문자열을 찾는 KMP 알고리즘 문제였습니다.

함정이 있기 때문에 문제의 주의사항을 주목해야합니다!

단, 펜, 파인애플, 사과, 펜 순서로 연결된 네 개의 물건만을 펜-파인애플-애플-펜으로 인정하며, 하나의 펜이 두 개의 펜-파인애플-애플-펜에 포함될 수 없다. 또한 펜, 사과, 파인애플, 펜 순서로 연결된 네 개의 물건은 펜-파인애플-애플-펜이 아니다.

즉, 기존에 풀던 KMP 알고리즘 문제와 달리 부분 문자열("pPAp")를 찾으면 마지막 p를 재활용하지 못하기 때문에 matched=pi[matched-1]로 초기화하지 않고 matched=0으로 해서 새로 찾기 시작해야합니다.


#include <iostream>

#include <string>

#include <vector>

using namespace std;

 

//N에서 자기 자신을 찾으면서 나타나는 부분 일치를 이용해 pi[]를 계산

//pi[i] = N[..i]의 접미사도 되고 접두사도 되는 문자열의 최대 길이

vector<int> getPartialMatch(const string &N)

{

        int M = N.size();

        vector<int> pi(M, 0);

        //KMP로 자기 자신을 찾는다

        //N N에서 찾는다

        //begin==0이면 자기 자신을 찾아버리니까 안됨!

        int begin = 1, matched = 0;

        //비교할 문자가 N의 끝에 도달할 때까지 찾으면서 부분 일치를 모두 기록한다

        while (begin + matched < M)

        {

                 if (N[begin + matched] == N[matched])

                 {

                         matched++;

                         pi[begin + matched - 1] = matched;

                 }

                 else

                 {

                         if (matched == 0)

                                 begin++;

                         else

                         {

                                 begin += matched - pi[matched - 1];

                                 matched = pi[matched - 1];

                         }

                 }

        }

        return pi;

}

 

//KMP 구현

int kmpSearch2(const string &H, const string &N)

{

        int n = H.size(), m = N.size();

        vector<int> result;

        vector<int> pi = getPartialMatch(N);

 

        //현재 대응된 글자의 수

        int matched = 0;

 

        //짚더미의 각 글자를 순회

        for (int i = 0; i < n; i++)

        {

                 //matched번 글자와 짚더미의 해당 글자가 불일치할 경우

                 //현재 대응된 글자의 수를 pi[matched-1]로 줄인다

                 while (matched > 0 && H[i] != N[matched])

                         matched = pi[matched - 1];

                 //글자가 대응될 경우, 이미 pPAp에 쓰여진 p가 아니라면

                 if (H[i] == N[matched])

                 {

                         matched++;

                         if (matched == m)

                         {

                                 result.push_back(i - m + 1);

                                 //matched = pi[matched - 1];

                                 matched = 0; //pPAp의 마지막 p 재활용 불가능

                         }

                 }

        }

        return result.size(); //pPAp 등장 횟수 반환

}

 

int main(void)

{

        int N;

        cin >> N;

 

        string original, target;

        cin >> original;

       

        target = "pPAp"; //-파인애플-애플-

 

        cout << kmpSearch2(original, target) << endl;

        return 0;

}



개발환경:Visual Studio 2017


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~


[참고] 프로그래밍 대회에서 배우는 알고리즘 문제해결전략

반응형

'알고리즘 > BOJ' 카테고리의 다른 글

백준 9019번 DSLR  (4) 2018.07.04
백준 2573번 빙산  (0) 2018.07.04
백준 2206번 벽 부수고 이동하기  (15) 2018.07.03
백준 3055번 탈출  (6) 2018.07.03
백준 1707번 이분 그래프  (2) 2018.07.02