KOI 지역본선 2013 고등부, no.5 바이러스 September 30, 2013

문제요약

$N$개의 정수 수열이 주어지는데, 이 정수 수열들 중 $K$만큼 공통 부분 수열이 존재 하는가를 묻는 문제이다. 이 때, 정수 수열들을 뒤집을 수도 있다$(1\leq{}N\leq{}100,1\leq{}M,K\leq{}1,000)$.

해법

정수를 비교하는거지만 결국 String Searching이랑 동일한 문제이므로 Rabin Karp (RK) Algorithm, kruth moriis pratt (KMP) Algorithm등을 쓰면 된다.

#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int n,k;
int m[111];
vector<int> v[111];
void calculate_pi(vector<int>& pi,const vector<int>& str){
    pi[0] = -1;
    int j = -1;
    for ( int i = 1 ; i < str.size() ; i++ ) {
        while ( j >= 0 && str[i] != str[j+1] ) j = pi[j];
        if ( str[i] == str[j+1] )
            pi[i] = ++j;
        else
            pi[i] = -1;
    }
}
bool match(vector<int> text,vector<int> pattern,vector<int> pi) {
    int j = -1;
    for ( int i = 0 ; i < text.size() ; i++ ) {
        while ( j >= 0 && text[i] != pattern[j+1]) j = pi[j];
        if ( text[i] == pattern[j+1] ) {
            j++;
            if ( j+1 == k ) {
                return true;
                j = pi[j];
            }
        }
    }
    return false;
}
bool go(int now) {
    vector<int> pi(v[0].size()-now);
    vector<int> __v;
    for ( int i = now ; i < v[0].size() ; i++ )
        __v.push_back(v[0][i]);
    calculate_pi(pi,__v);
    for ( int i = 1 ; i < n ; i++ ) {
        if ( !match(v[i],__v,pi) ) {
            reverse(v[i].begin(),v[i].end());
            if ( !match(v[i],__v,pi) )
                return false;
        }
    }
    return true;
}
int main() {
    scanf("%d%d",&n,&k);
    for ( int i = 0 ; i < n ; i++ ) {
        scanf("%d",&m[i]);
        for ( int j = 0 ; j < m[i] ; j++ ) {
            int t;
            scanf("%d",&t);
            v[i].push_back(t);
        }
    }
    bool ok = true;
    for ( int i = 0 ; i <= v[0].size()-k ; i++ ) {
        ok = go(i);
        if ( ok ) {
            printf("YES\n");
            return 0;
        }
    }
    ok = true;
    reverse(v[0].begin(),v[0].end());
    for ( int i = 0 ; i <=v[0].size()-k ; i++ ) {
        ok = go(i);
        if ( ok ) {
            printf("YES\n");
            return 0;
        }
    }
    printf("NO\n");
    return 0;
}

String Serching algorithm 을 포스팅하려다 어쩌다 다른길로 새버렸다.


Written by@sisobus
VUNO Inc. Software Engineer, Problem Solver

GitHubFacebook