ac自动机(字典树和kmp的延伸)(待更新)

多模匹配算法

模板题:
给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。(hdu2222)

#include 
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+7;
int a[maxn][26],fail[maxn],cnt[maxn];	//字典树,失败时的回溯指针,记录该单词出现次数 
int tot,rt,n;
string sz;
void insert(string s){
	rt=0;
	int len=s.size();
	for(int i=0;i<len;i++){
		int k=s[i]-'a';
		if(!a[rt][k])	a[rt][k]=++tot;
		rt=a[rt][k];
	}
	cnt[rt]++;
}

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

int query(string s){
	int ans=0,x=0;
	int len=s.size();
	for(int i=0;i<len;i++){
		x=a[x][s[i]-'a'];
		for(int j=x;j&&cnt[j]!=-1;j=fail[j]){
			ans+=cnt[j];
			cnt[j]=-1;
		}
	}
	return ans;
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>sz;
		insert(sz);
	}
	fail[0]=0;
	getfail();
	cin>>sz;
	cout<<query(sz);
}
/*
5 
she
he
say
shr
her
yasherhs

3
*/

分析过程时,最好弄个完全26叉树,根节点下再弄排根节点,看最下面的根节点的a数组,fail失溯指针不难理解。

加强版模板题:(洛谷P3796)
有 N 个由小写字母组成的模式串以及一个文本串 T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串 T 中出现的次数最多。
输出:第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

普通题解

我看见这题网上还有ac自动机和树状数组结合做的,时间复杂度更小 玄学题解

例题:题集

HDU - 2896 :记录哪些字符串出现和其出现次数。
POJ - 2778 :ac自动机+矩阵乘法的结合(待完善)

你可能感兴趣的:(字符串,算法)