標籤:ac自動機
ac自動機第一題
代碼參考kuangbin,用數組實現
思想參考的這個,寫得很詳細:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
#include<stdio.h> #include<algorithm>#include<math.h>#include<string.h>#include<queue>using namespace std;#define N 500010struct trie{//其實就是字典樹多了個失敗指標 int next[N][26],fail[N],end[N];int root,l;int newnode(){for(int i=0;i<26;i++) next[l][i]=-1;end[l++]=0;return l-1;}int init(){l=0;root=newnode();}void insert(char s[]){int len=strlen(s);int now=root;for(int i=0;i<len;i++) {if(next[now][s[i]-'a']==-1) next[now][s[i]-'a']=newnode();//如果沒出現過,就建立結點now=next[now][s[i]-'a'];//找到該結點的下一結點 }end[now]++;//一個單詞完,end+1 }void build(){//建立失敗指標,失敗指標是指當前結點的下一字元不匹配時,指向另一結點,再看另一結點的下一字元是否匹配 queue<int> q;fail[root]=root;//給根結點建失敗指標,方便其他結點賦值 for(int i=0;i<26;i++){if(next[root][i]==-1) next[root][i]=root;//把失配結點的下一結點指向根結點,其實就是失敗指標,方便查詢時首次賦值: now = next[now][buf[i]-'a']; 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<26;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]);}}}}int query(char s[]){int len=strlen(s);int now=root;int ans=0;for(int i=0;i<len;i++){now=next[now][s[i]-'a'];//注意這裡該字元不一定存在,但直接賦值了,所以在build裡要把next[][]置為父結點的失敗指標int tmp=now;while(tmp!=root){ans+=end[tmp];end[tmp]=0;tmp=fail[tmp];//用fail找相同首碼的串,其實這裡沒有匹配fail}}return ans;}void debug(){//模板裡的,方便調試 for(int i=0;i<l;i++){printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]); for(int j = 0;j < 26;j++) printf("%2d",next[i][j]); printf("]\n");}}};char s[N*2];trie ac;int main(){/*#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);#endif*/int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);ac.init();//每次重新初始化 for(int i=0;i<n;i++) {scanf("%s",s);ac.insert(s);}ac.build();//建失敗指標scanf("%s",s);printf("%d\n",ac.query(s));}return 0;}
HDU 2222 Keywords Search