AC自动机

Tire和kmp的结合版,自动机里面所谓的失败指针即kmp里的next指针,唯一的区别是自动机是树形的,kmp是数组的,所以在字典树上加一个失败指针就成了自动机了,所有代码都不需要变,多写一个计算失败指针的函数就行了,计算失败指针一遍bfs即可,之所以用bfs是保证计算某个节点之前他的所有可能转移回去的点的失败指针都已经计算过了(有点拗口= =!因为它的失败指针指向的点的高度一定比它低,bfs能保证它的上面的层的节点都已经计算过了)。

代码如下:

/*
TRIE结构,在使用前必须调用初始化init()!!!

在CX的字典树上修改
*/
#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
const int CTNUM = 26;  //储存字母的数目
const int STRNUM = 15000; //节点数目,绝对不能少于给定的字符串数目,一般给大点
const int MINCHAR='A';  //大小写分辨,如果混用或者不连续的话需要有对应的hash函数
struct TRIE
{
 int son[CTNUM];
 int count;
 int father;
}trie[STRNUM];
int fail[STRNUM];
int TNUM=1;
queue<int> q;
char s[200][200],ss[2000];
int dp[2000][2000],n;
#define INT_MAX 10000000
void init()
{
 memset(&trie[0],0,sizeof(TRIE));
 memset(&trie[1],0,sizeof(TRIE));
 TNUM=2;
}
int Ins(char *str,int len)
{
 int i;
 int cur=1;
 for(i=0;i<len;i++)
 {
  if( !trie[cur].son[str[i]-MINCHAR] )
  {
   memset( &trie[TNUM],0,sizeof(TRIE) );
   trie[TNUM].father=cur;
   cur=trie[cur].son[str[i]-MINCHAR]=TNUM++;
  }
  else cur=trie[cur].son[str[i]-MINCHAR];
  if (trie[cur].count>0) return cur;
 }
 trie[cur].count++;
 return cur;
}
void calc_fail()
{
 int i,k,p;
 fail[0]=0;
 fail[1]=0;
 memset(fail,0,sizeof(fail));
 while(!q.empty()) q.pop();
 q.push(1);
 while(!q.empty())
 {
  i=q.front();
  q.pop();
  if (trie[fail[i]].count==1)
   trie[i].count=1;
  for(k='A'-MINCHAR;k<='Z'-MINCHAR;k++)
  if (trie[i].son[k]!=0)
  {
   
                  int p=fail[i];
      while(p!=0&&trie[p].son[k]==0)
       p=fail[p];
      if (!p) fail[trie[i].son[k]]=1;
      else
      fail[trie[i].son[k]]=trie[p].son[k];
   q.push(trie[i].son[k]);
  }
 }
}

你可能感兴趣的:(AC自动机)