这道是个典型的AC自动机。
在trie的基础上添加fail指针,指向类似于KMP的next处。
大意是求一段文字中出现过多少某字典的词。
主要用于多串匹配。
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <queue>
- using namespace std;
- #define show(array,n) for( i = 0 ; i < n ; i++) printf("%d ",array[i]) ; puts("");
- #define REP(i,st,n) for( i = st ; i < n ; i++)
- #define ss(str) scanf("%s",str)
- struct node {
- node *next[26] , *fail ;
- int leaf ;
- node():leaf(0),fail(0) { memset(next,0,sizeof(next)); }
- };
- const int maxlen = 1000001 ;
- const int maxn = 10001 ;
- char diary[maxlen] ;
- node *root ;
- inline void init_trie() {
- root = new node();
- }
- inline void insert(char str[]) {
- node* ptr = root ;
- for( int i = 0 ; str[i] ; i++) {
- if( ptr->next[str[i]-'a'] == NULL ) ptr->next[str[i]-'a'] = new node();
- ptr = ptr->next[str[i]-'a'] ;
- }
- ptr->leaf++;
- }
- inline void build_ac_machine() {
- queue<node*> q ;
- q.push(root);
- while(!q.empty())
- {
- node* ptr = q.front(); q.pop();
- for( int i = 0 ; i < 26 ; i++) if( ptr->next[i] != NULL ) {
- // cal ptr->next[i]'s fail
- node* temp = ptr->fail ;
- while( temp != NULL && temp->next[i] == NULL ) temp = temp->fail ;
- if( temp == NULL ) ptr->next[i]->fail = root ;
- else ptr->next[i]->fail = temp->next[i] ;
- q.push(ptr->next[i]);
- }
- }
- }
- inline int match(char str[])
- {
- int ans , i , j , k ;
- node* ptr = root ;
- //i = strlen(str) ; str[i++] = '$'; str[i] = 0 ;
- for( i = ans = 0 ; str[i] ; i++) {
- j = str[i] - 'a' ;
- while( ptr!=root && ptr->next[j] == NULL ) ptr = ptr->fail ;
- ptr = ptr->next[j] ;
- if( ptr == NULL ) ptr = root ;
- node* temp = ptr ;
- while(temp!=NULL&&temp->leaf>=0) {
- ans += temp->leaf ;
- temp->leaf = -1 ; //-1,代表之后的fail都取过了,所以速度较快
- temp = temp->fail ;
- }
- }
- return ans ;
- }
- int main() {
- char str[64] ;
- int i , t , n ;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d",&n);
- init_trie();
- REP(i,0,n)
- {
- ss(str);
- insert(str);
- }
- build_ac_machine();
- ss(diary);
- printf("%d\n",match(diary));
- }
- }
转载于:https://blog.51cto.com/karsbin/948313