这里有一篇很好的文章---AC自动机详解
简要介绍一下AC自动机原理:
提前你应掌握的知识:
1、字典树---Trie-Tree
2、自动机一些简单入门级概念,如(状态)
3、KMP算法的next数组的生成原理
原理如下:
1、首先由模式串构建一颗字典树 2、根据KMP中next数组的原理,构建字典树Fail指针的前缀 3、输入主串,搜索
- <pre class="cpp" name="code">//
- // AC自动机模板
- // Author:chenzulong
- // Date: 2012年3月10日
- //
- #include<iostream>
- #include<algorithm>
- #include<functional>
- #include<queue>
- #include<string>
- #include<cstring>
- #include<exception>
- #include<typeinfo>
- #include<iterator>
- #ifndef AC_AUTOMAT
- #define AC_AUTOMAT
- class ACtomat{
- //some interfaces
- public:
- ACtomat(){
- }
- ~ACtomat(){
- delete root;
- }
- //initiliation the actomat
- bool ActomatInit(){
- try{
- index = 0;
- root = &Table[index];
- memset(Table[0].next,0,sizeof(Table[0].next));
- Table[0].cnt = 0;
- Table[0].prefix = NULL;
- }catch(...){
- std::cerr<<"Unknow Erro happen"<<std::endl;
- return false;
- }
- return true;
- }
- //input the str-pattern ,then conostruct the trie-tree
- bool insert(const std::string& str){
- Trie* r = root;
- std::string::const_iterator iter = str.begin();
- try{
- while(iter!=str.end()){
- int t = *iter -'a';
- if(!r->next[t]){
- index++;
- memset(Table[index].next,0,sizeof(Table[index].next));
- Table[index].prefix = NULL;
- Table[index].cnt = 0;
- r->next[t] = &Table[index];
- }
- r = r->next[t];
- iter++;
- }
- r->cnt++;
- }catch(...){
- std::cerr<<"Unknow Error happen"<<std::endl;
- delete r;
- r= 0;
- return false;
- }
- //constructor the fail-pointer
- if(ACtomatInitPrefix()){
- return true;
- }else{
- return false;
- }
- }
- //run the actomat
- bool ACtomatRun(const std::string& str,int& ans){
- Trie* p = root;
- Trie* tp = NULL;
- ans = 0;
- std::string::const_iterator iter = str.begin();
- try{
- while(iter!=str.end()){
- int t = *iter -'a';
- //recurisive
- while(!p->next[t]&&p!=root){
- p = p ->prefix;
- }
- p = p->next[t];
- if(!p){
- p = root;
- }
- tp = p;
- //go on matching,continue...
- while(tp!=root&&tp->cnt!=-1){
- ans +=tp->cnt;
- tp->cnt = -1;
- tp = tp->prefix;
- }
- iter++;
- }
- }catch(...){
- std::cerr<<"Unknow Error happend"<<std::endl;
- delete p;
- delete tp;
- return false;
- }
- return true;
- }
- //some constant variables
- private:
- enum{
- MAXN_WORD=1000001,
- MAXN_TOTAL = 500000
- };
- struct Trie{
- enum{
- MAXNT_NODE = 26
- };
- int cnt;
- Trie* next[MAXNT_NODE];
- Trie* prefix;
- };
- //some private variable
- private:
- Trie* root;
- Trie Table[MAXN_TOTAL];
- int index;
- //some functions whichs are used in class
- private:
- //get the fail-pointer table
- bool ACtomatInitPrefix(){
- Trie* r,*tmp,*father;
- try{
- r = root;
- std::queue<Trie*> q;
- q.push(root);
- root->prefix = NULL;
- while(!q.empty()){
- father = q.front();
- q.pop();
- for(int i=0;i<26;i++){
- if(father->next[i]){
- tmp = father->prefix;
- while(tmp&&!tmp->next[i]){
- tmp = tmp->prefix;
- }
- if(!tmp){
- father->next[i]->prefix = root;
- }else{
- father->next[i]->prefix = tmp->next[i];
- }
- q.push(father->next[i]);
- }
- }
- }
- }catch(...){
- std::cerr<<"Unkonw Error happen"<<std::endl;
- delete father;
- delete r;
- returnfalse;
- }
- //delete father;
- //delete r;
- return true;
- }
- };
- #endif
- int main(){
- int nCase;
- int num;
- std::string str;
- std::cin>>nCase;
- ACtomat* acMachine = new ACtomat;
- while(nCase--){
- std::cin>>num;
- acMachine->ActomatInit();
- while(num--){
- std::cin>>str;
- acMachine->insert(str);
- }
- std::cin>>str;
- int ans ;
- acMachine->ACtomatRun(str,ans);
- std::cout<<ans<<std::endl;
- }
- return 0;
- }
- </pre><br>
- <br>
- <pre></pre>
- <p></p>
- <pre></pre>
- <p></p>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>