hdu2222 Keywords Search

这题是简单的AC自动机,非常基础的自动机入门题,已经加上了个人对代码的注释,欢迎各位给予指正和修改。。。

#include <iostream>
using namespace std;
const int size = 26;
struct node
{
       int count;
       node *son[size];
       node *fail;
       node()
       {
             count = 0;
             fail = NULL;
             for (int i = 0; i < size; i ++){
                 son[i] = NULL;    
             }              
       }       
}*q[10000];


void insert(char *a, node *root)//建立字典树 
{
     int len =strlen(a);
     node *p = root;
     for (int i = 0; i < len; i ++){
         int k = a[i] - 'a';
         if (p -> son[k] == NULL){
            p -> son[k] = new node;         
         }    
         p = p -> son[k];
     }     
     p -> count ++;
}


void build_ac_automation(node *root)//建立AC自动机 
{
     int head = 0, tail = 0;
     root->fail = NULL;
     q[tail ++] = root;
     
     while (head != tail){
           node *temp = q[head ++];
           node *p = NULL;
           for (int i = 0; i < 26; i ++){
               if (temp -> son[i] != NULL){//如果字母('a'+i)存在于单词中 
                  if (temp == root){
                     temp -> son[i] -> fail = root;//如果为根结点,则fail指向root        
                  }
                  else {//如果不存在,则依次取当前字母(temp)和其父节点字母(p) 
                       p = temp -> fail;
                       while (p != NULL){//当前字母的父节点存在 
                             if (p -> son[i] != NULL){//遍历看其父节点中有无同样的字母'a'+i 
                                temp -> son[i] -> fail = p -> son[i];//如果有,则改变当前temp的fail指针使其指向父节点的('a'+i)字母 
                                break;      
                             }      
                             p = p -> fail;//继续向上探询父节点 
                       }
                       if (p == NULL)temp -> son[i] -> fail = root; //如果遍历到最上层都没有找到则将fail指向root 
                  }
                  q[tail ++] = temp -> son[i];//当前点继续入队实现BFS;
               }    
                
           }               
     }     
}


int find(node *root, char *a)
{
    int ans = 0, len = strlen(a);
    node *p = root;
    for (int i = 0; i < len; i ++){
        int k = a[i] - 'a';
        //如果当前字母没有匹配项则匹配其下一个fail指向的字母,如果都没有则回到根结点 
        while (p -> son[k] == NULL && p != root)p = p -> fail;
        //匹配当前字母 
        p = p -> son[k];
        //如果当前没有字母,则回到根节点   
        p = (p == NULL)? root : p;
        node *temp = p;
        //如果当前存在字母(但是不知道是否相同)且没有被匹配过,则查找能够匹配的字母个数
        while (temp != root && temp -> count != -1){
              ans += temp -> count;
              temp -> count = -1;
              temp = temp -> fail;
        }
    }
    return ans;

char word[51], word1[1000010];
int main()
{
    
    int t, n;
    scanf("%d", &n);
    while (n --){
          scanf("%d", &t);
          node *root;
          root = new node;
          while (t --){
                scanf("%s", word);
                insert(word, root);  
          }
          build_ac_automation(root);
          scanf("%s", word1);
          printf("%d\n", find(root, word1));
    }
    return 0;    
}

你可能感兴趣的:(hdu2222 Keywords Search)