HDU 2222 Keywords Search(AC自动机)

AC自动机,这个名字有没点虎。乍一看有没有自动AC题目的意思,就是万精油模板,其实是一个匹配算法。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。

#include<stdio.h>
#include<string.h>
#define MAXD 500010
#define MAXT 1000010
char b[60], txt[MAXT];
int N, next[MAXD][26], flag[MAXD], P[MAXD], q[MAXD], e, cnt;
void insert(int cur, int k)
{    
	++ e;
    flag[e] = 0;
    memset(next[e], 0, sizeof(next[e]));
    next[cur][k] = e;
}
void update()
{    
	int i, j, u, x, front, rear; 
	front = rear = 0;
    P[0] = q[rear ++] = 0; 
	while(front < rear)  
	{     
		u = q[front ++]; 
		for(i = 0; i < 26; i ++)
            if(next[u][i]) 
			{           
				x = next[u][i]; 
				if(u == 0)  
					P[x] = 0;  
				else    
				{   
					for(j = P[u]; j != 0; j = P[j])
                        if(next[j][i])  
						{    
							P[x] = next[j][i];   
							break;    
						}    
						if(j == 0)    
							P[x] = next[0][i]; 
				}      
				q[rear ++] = next[u][i];  
			}  
	}
}
int main()
{  
	int t;  
	scanf("%d", &t); 
	while(t --)  
	{     
		int i, j, k, cur;
		scanf("%d", &N);
		e = 0;    
		memset(next[e], 0, sizeof(next[e]));
		for(i = 0; i < N; i ++)
		{        
			scanf("%s", b);
			cur = 0;   
			for(j = 0; b[j]; j ++)
			{           
				k = b[j] - 'a'; 
				if(!next[cur][k])
					insert(cur, k);
				cur = next[cur][k]; 
			}       
			++ flag[cur];
		}
		int t; 
		update();  
		scanf("%s", txt);
		j = cnt = 0; 
		for(i = 0; txt[i]; i ++) 
		{     
			k = txt[i] - 'a';
			while(j > 0 && !next[j][k])  
				j = P[j];  
			j = next[j][k];     
			for(t = j; t > 0; t = P[t]) 
			{         
				if(flag[t] >= 0)   
				{           
					cnt += flag[t];       
					flag[t] = -1;  
				}           
				else         
					break;  
			}  
		}  
		printf("%d\n", cnt);
    }   
	return 0;
}

 

全名:Aho-Corasick automation。要搞懂AC自动机,先得有模式树(字典树)TrieKMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。难度很大,KMP和Trie都是我不怎么熟悉的地域,某一论文(全英文)很好的阐述了这个算法,不过就是英文难看了,我也没去看,就着网上其他人的文章看了看。

顺便给个地址:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

感觉这位同学写的不错了。

这题是入门的一个模板题,需要注意的是单词列表中可能有重复的单词,但这些重复的单词应看做不同的,因此建字典树时做标记的时候,把原来的赋值为1的操作变为自加1的操作。

posted @ 2012-02-06 23:16  Lxsec  阅读(235)  评论(0编辑  收藏  举报