AC自动机
先留个眼,以后慢慢看
重点1:fail指针的插入
如果该字符存在,fail指针指向 父节点fail指针指向节点 的该字符的编号值
不然 该节点trie树节点指向 父节点fail指针指向节点 的该字符的编号值
究极复杂
void h()
{
queue<int>que;
int q=0;
for(int i=0;i<26;i++)
{
if(a[q].num[i])
{
a[a[q].num[i]].fail=0;
que.push(a[q].num[i]);
}
}
while (que.size())
{
int t=que.front();que.pop();
for(int i=0;i<26;i++)
{
if(a[t].num[i])
{
a[a[t].num[i]].fail=a[a[t].fail].num[i];
que.push(a[t].num[i]);
}
else a[t].num[i]=a[a[t].fail].num[i];
}
}
}
重点2:
查询 循环什么意思一直看不明白
int quary(char *s,int n)
{
int q=0,ans=0,j;
for(int i=0;i<n;i++)
{
q=a[q].num[s[i]-'a'];
for (j = q; j && ~num[j]; j = a[j].fail)
{
ans = ans + num[j];
num[j] = -1;
}
}
return ans;
}
ac代码:
#include<bits/stdc++.h>
using namespace std;
struct node
{
int num[30];
int fail;
};
node *a=new node[1000000];
int *num=new int[10000000];
int t=0;
void f()
{
for(int i=0;i<100000;i++)
{
memset(a[i].num,0,sizeof(a[i].num));
a[i].fail=0;
}
}
vector<string>v;
void inser(char *s,int n)
{
int p=0;
for(int i=0;i<n;i++)
{
int k=s[i]-'a';
if(a[p].num[k]==0)
{
a[p].num[k]=++t;
}
p=a[p].num[k];
}
num[p]++;
}
int getn(char *s,int n)
{
int p=0;
for(int i=0;i<n;i++)
{
int k=s[i]-'a';
if(a[p].num[k])
{
p=a[p].num[k];
}
else return 0;
}
return num[p];
}
void h()
{
queue<int>que;
int q=0;
for(int i=0;i<26;i++)
{
if(a[q].num[i])
{
a[a[q].num[i]].fail=0;
que.push(a[q].num[i]);
}
}
while (que.size())
{
int t=que.front();que.pop();
for(int i=0;i<26;i++)
{
if(a[t].num[i])
{
a[a[t].num[i]].fail=a[a[t].fail].num[i];
que.push(a[t].num[i]);
}
else a[t].num[i]=a[a[t].fail].num[i];
}
}
}
int quary(char *s,int n)
{
int q=0,ans=0,j;
for(int i=0;i<n;i++)
{
q=a[q].num[s[i]-'a'];
for (j = q; j && ~num[j]; j = a[j].fail)
{
ans = ans + num[j];
num[j] = -1;
}
}
return ans;
}
int main()
{
//freopen("C:\\Users\\Lenovo\\Desktop\\input.txt","r",stdin);
int n,k;
char s[90];
char *ss=new char[1000000];
//scanf("%d",&n);
//while (n--)
{
memset(num,0,sizeof(num));f();v.clear();
scanf("%d",&k);
while (k--)
{
getchar();
scanf("%s",s);
inser(s,strlen(s));
//v.push_back(s);
}
scanf("%s",ss);
h();
cout<<quary(ss,strlen(ss))<<endl;
}
return 0;
}
kmp也行,但是超时,不太会优化
#include <bits/stdc++.h>
using namespace std;
int tim,n;
char s[1000002];
struct node
{
char s[55];
int next[55];
};
node *arr=NULL;
void add(char *s,int l,int t)
{
arr[t].next[0]=-1;
int j=0,k=-1;
while (j<l-1)
{
if(k==-1||s[j]==s[k])
{
j++;k++;
arr[t].next[j]=k;
}
else
k=arr[t].next[k];
}
}
int kmp(char *s,int ls,char *h,int lh,int t)
{
int i=0,k=0;
while (i<ls&&k<lh)
{
if(k==-1||s[i]==h[k])
{
i++;k++;
}
else
k=arr[t].next[k];
}
if(k>=lh)return i-lh;
else return -1;
}
int cacu()
{
int c=0;
for(int i=0;i<n;i++)
{
int ans=kmp(s,strlen(s),arr[i].s,strlen(arr[i].s),i);
if(ans!=-1)c++;
}
return c;
}
int main()
{
//freopen("C:\\Users\\Lenovo\\Desktop\\input.txt","r",stdin);
scanf("%d",&tim);
while (tim--)
{
scanf("%d",&n);
arr=new node[n];
for(int i=0;i<n;i++)
{
getchar();
scanf("%s",arr[i].s);
add(arr[i].s,strlen(arr[i].s),i);
}
getchar();
scanf("%s",s);
cout<<cacu()<<endl;
}
return 0;
}