#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN=510;//字典树中的单词个数
const int MAXL=510;//每个单词的最大长度
const int MAXS=510;//输入的最大长度
struct Trie
{
int next[MAXL*MAXN][128],fail[MAXL*MAXN],end[MAXL*MAXN];
int root,L;
int newnode()
{
for(int i = 0;i < 128;i++)
next[L][i] = -1;
end[L++] = -1;
return L-1;
}
void init()
{
L = 0;
root = newnode();
}
void insert(char s[],int id)
{
int len = strlen(s);
int now = root;
for(int i = 0;i < len;i++)
{
if(next[now][s[i]] == -1)
next[now][s[i]] = newnode();
now=next[now][s[i]];
}
end[now]=id;
}
void build()
{
queue<int>Q;
fail[root] = root;
for(int i = 0;i < 128;i++)
if(next[root][i] == -1)
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0;i < 128;i++)
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];//直指指针:无论如何都不可能匹配,指向父节点的该方向
else
{
fail[next[now][i]] = next[fail[now]][i];//失配指针, 虽然有指向,但是为了标记出下面那种特殊情况而必须建立的指针
Q.push(next[now][i]);
}
}
}//总而言之,这里的失配指针不是起到失配重指的作用(这不是句人话),next才实现了这样的功能
//但是失配指针可以帮助你遍历所有子情况
bool used[MAXN];
bool query(char buf[],int n,int id)
{
int len = strlen(buf);
int now = root;
memset(used,false,sizeof(used));
bool flag = false;
for(int i = 0;i < len;i++)
{
now = next[now][buf[i]];
int temp = now;
while(temp != root)
{
if(end[temp] != -1)
{
used[end[temp]] = true;
flag = true;
}
temp = fail[temp];//等同于给abcd、bc这样的病毒码中abcd中bc加上标记
}
}
if(!flag)return false;
printf("web %d:",id);
for(int i = 1;i <= n;i++)
if(used[i])
printf(" %d",i);
printf("\n");
return true;
}
};
char buf[MAXS];
Trie ac;
int main(){
int n;
while(~scanf("%d",&n)){
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",buf);
ac.insert(buf,i);
}
ac.build();
int t;
scanf("%d",&t);
int ans=0;
for(int i=1;i<=t;i++){
scanf("%s",buf);
if(ac.query(buf,n,i)){
ans++;
}
}
printf("total: %d\n",ans);
}
return 0;
}
模板积累——AC自动机(结构体类方法版)
最新推荐文章于 2023-01-30 22:56:09 发布