$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 을 포스팅하려다 어쩌다 다른길로 새버렸다.