给N个模式串,每个不超过个字符,再给M个句子,句子长度<100 判断每个句子里是否包含模式串
N < 10, M < 10 ,字符都是小写字母
5 8
abcde
deft
cake
ab
f
abcdkef
abkef
bcd
bra
add
ab
qab
f
//
// main.cpp
// Richard
//
// Created by 邵金杰 on 16/7/26.
// Copyright © 2016年 邵金杰. All rights reserved.
//
#include<iostream>
#include<queue>
using namespace std;
#define letters 26
const int maxn=100+10;
//存放26个子结点,和前驱结点
struct node{
node *pchild[letters];
node *prev;
bool badnode;
//初始化
void intil(){
memset(pchild,0,sizeof(pchild));
prev=NULL;
badnode=false;
}
}tree[maxn];
int nCountNode=0;
//把输出的模式串建成一棵树,七点在tree[1],然后从tree+nCountNode,也就是tree[2]开始,最后更新危险结点
void Insert(node *p,string s)
{
for(int i=0;s[i];i++)
{
if(p->pchild[s[i]-'a']==NULL)
{
p->pchild[s[i]-'a']=tree+nCountNode;
nCountNode++;
}
p=p->pchild[s[i]-'a'];
}
p->badnode=true;
}
//构建前驱结点,当然要先初始化tree[0],初始化tree[0]尤为重要,因为它能在无法配对时,退回到tree[0],然后由tree[0]再到tree[1],开始新一轮从根结点开始的配对,队列的左右时把从2开始的结点设置上前驱结点,前驱结点是指当前结点的父结点的前驱结点,若改前驱结点的子结点有当前结点的字母,那么这个子结点就是当前结点的前驱结点,如果没有,那么继续寻找前驱结点。
void BuildDfa()
{
for(int i=0;i<letters;i++)
tree[0].pchild[i]=tree+1;
tree[0].prev=NULL;
tree[1].prev=tree;
queue<node*> q;
q.push(tree+1);
while(!q.empty())
{
node *p=q.front();q.pop();
for(int i=0;i<letters;i++)
{
node *a=p->pchild[i];
if(a)
{
node *prev=p->prev;
while(prev)
{
if(prev->pchild[i]){
a->prev=prev->pchild[i];
if(prev->badnode) a->badnode=true;
break;
}
else
prev=prev->prev;
}
q.push(a);
}
}
}
}
bool SearchDfa(string s)
{
node *p=tree+1;
for(int i=0;s[i];i++)
{
while(true)
{
if(p->pchild[s[i]-'a']){
p=p->pchild[s[i]-'a'];
if(p->badnode==true) return true;
break;
}
else
p=p->prev;
}
}
return false;
}
int main()
{
int n,m;
string s;
cin>>n>>m;
nCountNode=2;
for(int i=0;i<n;i++)
{
cin>>s;
Insert(tree+1,s);
}
BuildDfa();
for(int i=0;i<m;i++)
{
cin>>s;
if(SearchDfa(s)) cout<<"True"<<endl;
else cout<<"False"<<endl;
}
return 0;
}