ac自动机:
给你若干个单词,判断一段文字里边这些单词出现了吗,在哪出现,出现几次?
首先是字典树模板:
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; const int maxn=1e3+50; struct trie_node{ int count; trie_node*son[26]; }; trie_node* new_node() { trie_node* pnode=new trie_node(); pnode->count=0; for(int i=0;i<26;i++)pnode->son[i]=NULL; return pnode; } void trie_insert(trie_node *root,char key[]) { trie_node* node=root; char *p=key; while(*p) { if(node->son[*p-'a']==NULL)node->son[*p-'a']=new_node(); node=node->son[*p-'a']; ++p; } node->count+=1; } int trie_search(trie_node *root,char key[]) { trie_node*node=root; char *p=key; while(*p&&node!=NULL) { node=node->son[*p-'a']; ++p; } if(node==NULL)return 0; else return node->count; } int main() { int n,q,i,j; char s[20]; trie_node *root; root=new_node(); scanf("%d%d",&n,&q); while(n--) { scanf("%s",s); trie_insert(root,s); } while(q--) { scanf("%s",s); printf("%d\n",trie_search(root,s)); } }
然后是ac自动机:字典树+fail指针 重点在getfail函数
例题是 hdu5880
一整天,一直被卡MLE,改成指针形式的动态开点也卡。
然后去搜,终于搜到一篇博客。
博客说:不要一次性memset,而是,用到一个点,memset一次。
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #define debug printf("!"); using namespace std; const int maxn=1e6+5; struct T{ int fail; int vis[26]; int dep; }ac[maxn]; int cnt; char s[maxn]; void init(int t) { ac[t].fail=ac[t].dep=0; memset(ac[t].vis,0,sizeof(ac[t].vis)); } inline void insert(char *s) { int len=strlen(s),i,p=0,dep=0; for(i=0;i<len;i++) { dep++; if(!ac[p].vis[s[i]-'a']) { ac[p].vis[s[i]-'a']=++cnt; init(cnt); } p=ac[p].vis[s[i]-'a']; } ac[p].dep=dep; } inline void get_fail() { queue<int>que; for(int i=0;i<26;i++) { if(ac[0].vis[i]) { ac[ac[0].vis[i]].fail=0; que.push(ac[0].vis[i]); } } while(!que.empty()) { int u=que.front(); que.pop(); for(int i=0;i<26;i++) { if(ac[u].vis[i]!=0) { ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i]; que.push(ac[u].vis[i]); } else ac[u].vis[i]=ac[ac[u].fail].vis[i]; } } } void query(char s[]) { int len=strlen(s),i,j,k,t=0,p=0; for(i=0;i<len;i++) { char c=s[i]; if('A'<=c&&c<='Z')c+=32; else if(!('a'<=c&&c<='z')) { p=0;continue; } p=ac[p].vis[c-'a']; for(j=p;j;j=ac[j].fail) { if(ac[j].dep) { for(k=i-ac[j].dep+1;k<=i;k++)s[k]='*'; } } } } int main() { int n,T; scanf("%d",&T); while(T--) { cnt=0; init(0); scanf("%d",&n); while(n--) { scanf("%s",s); insert(s); } get_fail(); getchar(); cin.getline(s,maxn); query(s); printf("%s\n",s); } }