AC自动机的理解

题意  多个 B串 匹配 A 串

学完ac自动机,发现其实它与KMP有异曲同工之妙。

我们知道,KMP要先对B串进行自我匹配求出 F 数组,同样的,AC自动机也要对所有B串进行自我匹配。

区别在于KMP中,B串只有一个,所以我们直接循环进行,但是ac自动机中B串有多个,每个都用循环处理的话时间复杂度不支持,所以我们考虑用trie树,在trie树上建立类似于KMP中的 F[ n ] 数组;

首先复习一下 F 数组的意义     F[ i ]  表示在trie书上 从根节点开始以 i 为结尾的串的后缀 与 根节点到 F[ i ] 代表的子串相同  (当前串的某些后缀 与某些串的前缀相同)

怎么求出 F 数组呢  我们使用BFS的方法   

现将根节点的存在的子节点放入队列中

然后依次取出队首,对于当前节点now,我们遍历它的a-z这些子节点c[now][a-z],假设存在 c[now][a],那么将这个子节点c[now][a]的 F 指向 当前F[now] 的子节点 a。 即F[ c[now][a] ] = c[ F[now] ][a],   然后令u节点入队 。 这样便能满足后缀等于前缀。(想想清楚)

对于不存在的  c[now][a]    令  c[now][a]=c[ F[now] ][ a ]

假设A串下一个字母是 a  而,当前节点 now 的 子节点不存在  c[now][a] ,那么匹配失败,按照推理需要跳到c[ f[now] ][a],所以便有了  now没有子节点a时 c[now][a]=c[ F[now] ][a];

void ins(char *s){
		int len=strlen(s);
		int now=0;
		for(int i=0;i<len;i++){
			int u=s[i]-'a';
			if(!c[now][u])c[now][u]=++cnt;
			now=c[now][u];
		}
		val[now]++;
	}


void build(){
		for(int i=0;i<26;i++)if(c[0][i])fail[c[0][i]]=0,q.push(c[0][i]);
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=0;i<26;i++){
				if(c[x][i])fail[c[x][i]]=c[fail[x]][i],q.push(c[x][i]);
				else c[x][i]=c[fail[x]][i];
			}
		}
		
	}
	

这样我们便成功建立了F 数组  并且  完善了trie树

下面便是遍历A串了

假设遍历到了now     下一个字母是a    那么  now=c[now][a]

到达了 新的节点   我们要统计这是否是一个单词的结尾   ,同时 我们还要统计  F[now] 是否是单词的结尾   还有F[ F[now] ] 是否是单词的结尾, 一直到根节点 。

为什么呢,  因为到达当前节点now  如果有标记,也只能说根节点到now代表了一个B串  那么是否有可能   根节点到now路径上的 某一个点u 到now也代表了一个B串呢,显然是有可能的,s[u-now] 这个子串我们插入的时候是从根节点开始的。

而这个节点 u 到 now  是 以now为结尾的串的后缀 刚好就能够满足 F[now]的定义。

所以每走一个点,我们要判断 一直F[now]直到根节点

int  query(char *s){
		int len=strlen(s);
		int ans=0,now=0;
		for(int i=0;i<len;i++){
			int u=s[i]-'a';
			now=c[now][u]; // 走 到now节点
			for(int t=now;t&&val[t]!=-1;t=fail[t])ans+=val[t],val[t]=-1;
            要依次判断 F[now] 是不是某个单词的结尾  累加答案直到根节点
		}
		
		return ans;
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值