您的位置:首页 > 其它

AC自动机精讲

2016-06-22 11:09 204 查看
http://www.cnblogs.com/Booble/archive/2010/12/05/1897121.html

//hdu2222
//ACauto
//构造失败指针:设当前节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。
//匹配(1)当前字符匹配,只需沿该路径走向下一个节点继续匹配即可;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配.重复这2个过程中的一个,直到模式串走完。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#define cha 26
#define Root 0
#define N 500001
using namespace std;
struct node{
int data;//结点信息
int count;//从根到此处是否是关键字,并且记录是多少个关键字的结尾
int fail;
int next[cha];
}tree
;

void init(node &a,int data){
a.data = data;
a.count = 0;
a.fail = Root;
for(int i=0;i<cha;i++)
a.next[i] = -1;
}

int k = 1;
void Insert(char s[]){
int p = Root;
for(int i=0;s[i];i++){
int data = s[i]-'a';
if(tree[p].next[data]==-1){//不存在该结点
init(tree[k],data);
tree[p].next[data] = k;
k++;
}
p = tree[p].next[data];
}
tree[p].count++;
}

queue<node> q;
void AC_automation(){
q.push(tree[Root]);
while(!q.empty()){
node k = q.front();
q.pop();
for(int j=0; j<cha; j++){
if( k.next[j]!=-1 ){
if( k.data == -1 ) tree[k.next[j]].fail = Root;
else{
int t = k.fail;
while( t!=Root && tree[t].next[j]==-1 ) t = tree[t].fail;
tree[ k.next[j] ].fail = max( tree[t].next[j], Root );
}
q.push(tree[k.next[j]]);
}
}
}
}

int get_ans(char s[]){
int k=Root, ans = 0;
for(int i=0;s[i];i++){
int t = s[i] - 'a';
while(tree[k].next[t]==-1 && k ) k = tree[k].fail;
k = tree[k].next[t];
if(k==-1){ k = Root;continue;}
int j = k;
while( tree[j].count ){
ans += tree[j].count;
tree[j].count = 0;
j = tree[j].fail;
}
//下面两句很重要,如果走到头以后当前字母不是关键字终点然而其fail指针指向字母是关键字终点的话,
//应当加入此关键值,而网上大多数程序忽视了这一点导致hdu的discuss里反例过不了
ans += tree[ tree[j].fail ].count;
tree[ tree[j].fail ].count = 0;
}
return ans;
}

char tar[2*N];
int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init(tree[Root],-1);
char a[55];
while(n--){
scanf("%s",a);
Insert(a);
}
AC_automation();
scanf("%s",tar);
printf("%d\n",get_ans(tar));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: