AC自动机以及KMP模板

AC自动机

 
Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法。
要学会AC自动机,我们必须知道什么是 Trie,也就是字典树。 Trie树,又称单词查找树或 键树,是一种 树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
应用
一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。
要搞懂AC自动机,先得有模式树( 字典树)Trie和 KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵 Trie树,构造失败 指针和模式匹配过程。

//AC自动机模板
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 5;
const int MAX = 10000000;

struct node
{
	node *next[26];
	node *fail;
	int sum;
};

node *root;
node *q[MAX];          //队列
char partner[maxn];
char s[105];
int head, tail;
int cnt;

//建立字典树
void Insert(char *s)
{
	node *p = root;
	for(int i=0; s[i]; i++)
	{
		int x = s[i] - 'a';
		if(p->next[x]==NULL)
		{
			node *temp = (node *)malloc(sizeof(node));
			for(int j=0; j<26; j++)
				temp->next[j] = 0;
			temp->sum = 0;
			temp->fail = 0;
			p->next[x] = temp;
		}
		p = p->next[x];
	}
	p->sum++;
}

//用队列实现fail
void build_fail_pointer()
{
	head = 0;
	tail = 1;
	q[head] = root;
	while(head < tail)
	{
		node *temp = q[head++];
		for(int i=0; i<26; i++)
		{
			if(temp->next[i])
			{
				if(temp == root)
				{
					temp->next[i]->fail = root;
				}
				else
				{
					node *r = temp->fail;
					while(r)
					{
						if(r->next[i])
						{
							temp->next[i]->fail = r->next[i];
							break;
						}
						r = r->fail;
					}
					if(r==NULL)
						temp->next[i]->fail = root;
				}
				q[tail++] = temp->next[i];
			}
		}
	}
}

//匹配单词
void ac_automation(char *partner)
{
	node *p = root;
	int len = strlen(partner);
	for(int i=0; i<len; i++)
	{
		int x = partner[i]-'a';
		while(!p->next[x] && p!=root)
			p = p->fail;
		p = p->next[x];
		if(!p)
			p = root;
		node *temp = p;
		while(temp != root)
		{
			if(temp->sum >= 0)
			{
				cnt += temp->sum;
				temp->sum = -1;
			}
			else
				break;
			temp = temp->fail;
		}
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		root = (node *)malloc(sizeof(node));
		for(int i=0; i<26; i++)
			root->next[i] = 0;
		root->sum = 0;
		root->fail = 0;
		int n;
		scanf("%d", &n);
		getchar();
		for(int i=1; i<=n; i++)
		{
			gets(s);
			Insert(s);
		}
		gets(partner);
		cnt = 0;
		build_fail_pointer();
		ac_automation(partner);
		printf("%d\n", cnt);
	}
	return 0;
}



//KMP模板
//T是模式串
void getNext(char *T)
{
    int j, k, tlen = strlen(T);
    j = 0; k = -1; next[0] = -1;
    while(j < tlen)
        if(k == -1 || T[j] == T[k])
            next[++j] = ++k;
        else
            k = next[k];
}
//返回模式串T在主串S中首次出现的位置
//返回的位置是从0开始的。
int KMP_Index(char *T, char *S)
{
    int i = 0, j = 0;
    getNext(T);
    int slen = strlen(S);
    int tlen = strlen(T);
    while(i < slen && j < tlen)
    {
        if(j == -1 || S[i] == T[j])
        {
            i++; j++;
        }
        else
            j = next[j];
    }
    if(j == tlen)
        return i - tlen;
    else
        return -1;
}


AC自动机模板题目:HDU 2222

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222


猜你喜欢

转载自blog.csdn.net/qq_31281327/article/details/76465976
今日推荐