个人认为trie,KMP,AC自动机是思想非常明确的,AC自动机的性质是与KMP算法的思想类似的(失配后跳转)
而KMP是线性的,AC自动机是在tire树上跑KMP,为方便那些不会用指针的小朋友(我也不会。。。。)
我的tire树,kmp算法的next,AC自动机的fail全是用数组实现的!!!!(还有谁???!!!)
所以
上板子
1.KMP
2.TRIE
3.AC自动机
void make() { nxt[1]=0; for(int i=2; i<=len1; i++) { int j=nxt[i-1]; while(j>0 && s[i]!=s[j+1])j=nxt[j]; if(s[i]==s[j+1])nxt[i]=j+1; else nxt[i]=0; } return; } void kmp(int len){ int j=0; for(int i=1;i<=len1;++i){ while(j&&s[j+1]!=s[i])j=nxt[j]; if(s[j+1]==s[i])j++; if(j>=len)tot++,j=nxt[j]; } }
struct data { int num[28]; int cnt; } node[1000001]; char s[100000]; void build(char*str) { int now=0; while(*str) { int k=int(*str-'a'); if(!node[now].num[k])Au++,node[now].num[k]=Au; now=node[now].num[k],node[now].cnt++; str++; } } void print(char*str) { int now=0; while(*str) { int k=int(*str-'a'); if(!node[now].num[k]) { printf("0 "); return; } now=node[now].num[k]; str++; } }
struct data{ int num[27],id; }trie[10001]; queue<int>bfs; int fail[10001]; int n,tot,len; int ans[10001]; char s[10001][51]; char t[10000001]; void add(int q){//建一棵神奇的字典树 int now=0; int head=0; while(head!=len){ int k=int(s[q][head]-'a'); if(!trie[now].num[k])trie[now].num[k]=++tot; now=trie[now].num[k]; if(head==len-1){trie[now].id=q;break;} head++; } } void bbfs(){ bfs.push(0); while(!bfs.empty()){ int w=bfs.front(); for(int i=0;i<=25;++i)if(trie[w].num[i]){//若有 int u=trie[w].num[i]; int fa=fail[w]; while((fa)&&(trie[fa].num[i]==0))fa=fail[fa];//如果父亲的fail无其相应字母子节点,一直跳下去直到根节点 if((trie[fa].num[i]!=u)&&(trie[fa].num[i]))//不等于本身 fail[u]=trie[fa].num[i]; bfs.push(u);//入队 } bfs.pop();//队首元素出队 } } void make(){ int now=0; for(int i=0;i<len;++i){ int k=int(t[i]-'a'); while(!trie[now].num[k]&&now!=0)now=fail[now]; now=trie[now].num[k]; int KMP=now;//根据fail数组性质,要一直while下去!!!直至根节点 while(KMP)ans[trie[KMP].id]++,KMP=fail[KMP]; } }