ac自动机模板(hdu2222)

来源:互联网 发布:淘宝收费吗 编辑:程序博客网 时间:2024/05/22 05:39
  1. 具体代码;  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. struct Node  
  6. {  
  7.     int cnt;//是否为该单词的最后一个结点   
  8.     Node *fail;//失败指针   
  9.     Node *next[26];//Trie中每个结点的各个节点   
  10. }*queue[500005];//队列,方便用BFS构造失败指针   
  11. char s[1000005];//主字符串   
  12. char keyword[55];//需要查找的单词   
  13. Node *root;//头结点   
  14. void Init(Node *root)//每个结点的初始化   
  15. {  
  16.     root->cnt=0;  
  17.     root->fail=NULL;  
  18.     for(int i=0;i<26;i++)  
  19.         root->next[i]=NULL;  
  20. }  
  21. void Build_trie(char *keyword)//构建Trie树   
  22. {  
  23.     Node *p,*q;  
  24.     int i,v;  
  25.     int len=strlen(keyword);  
  26.     for(i=0,p=root;i<len;i++)  
  27.     {  
  28.         v=keyword[i]-'a';  
  29.         if(p->next[v]==NULL)  
  30.         {  
  31.             q=(struct Node *)malloc(sizeof(Node));  
  32.             Init(q);  
  33.             p->next[v]=q;//结点链接   
  34.         }  
  35.         p=p->next[v];//指针移动到下一个结点   
  36.     }  
  37.     p->cnt++;//单词最后一个结点cnt++,代表一个单词   
  38. }  
  39. void Build_AC_automation(Node *root)  
  40. {  
  41.     int head=0,tail=0;//队列头、尾指针   
  42.     queue[head++]=root;//先将root入队   
  43.     while(head!=tail)  
  44.     {  
  45.         Node *p=NULL;  
  46.         Node *temp=queue[tail++];//弹出队头结点   
  47.         for(int i=0;i<26;i++)  
  48.         {  
  49.             if(temp->next[i]!=NULL)//找到实际存在的字符结点   
  50.             { //temp->next[i] 为该结点,temp为其父结点   
  51.                 if(temp==root)//若是第一层中的字符结点,则把该结点的失败指针指向root   
  52.                     temp->next[i]->fail=root;  
  53.                 else  
  54.                 {  
  55.                     //依次回溯该节点的父节点的失败指针直到某节点的next[i]与该节点相同,  
  56.                     //则把该节点的失败指针指向该next[i]节点;   
  57.                     //若回溯到 root 都没有找到,则该节点的失败指针指向 root  
  58.                     p=temp->fail;//将该结点的父结点的失败指针给p   
  59.                     while(p!=NULL)  
  60.                     {  
  61.                         if(p->next[i]!=NULL)  
  62.                         {  
  63.                             temp->next[i]->fail=p->next[i];  
  64.                             break;  
  65.                         }  
  66.                         p=p->fail;  
  67.                     }  
  68.                     //让该结点的失败指针也指向root   
  69.                     if(p==NULL)  
  70.                         temp->next[i]->fail=root;  
  71.                 }  
  72.                 queue[head++]=temp->next[i];//每处理一个结点,都让该结点的所有孩子依次入队   
  73.             }  
  74.         }  
  75.     }  
  76. }  
  77. int query(Node *root)  
  78. { //i为主串指针,p为模式串指针   
  79.     int i,v,count=0;  
  80.     Node *p=root;  
  81.     int len=strlen(s);  
  82.     for(i=0;i<len;i++)  
  83.     {  
  84.         v=s[i]-'a';  
  85.         //由失败指针回溯查找,判断s[i]是否存在于Trie树中   
  86.         while(p->next[v]==NULL && p!=root)  
  87.             p=p->fail;  
  88.         p=p->next[v];//找到后p指针指向该结点   
  89.         if(p==NULL)//若指针返回为空,则没有找到与之匹配的字符   
  90.             p=root;  
  91.         Node *temp=p;//匹配该结点后,沿其失败指针回溯,判断其它结点是否匹配   
  92.         while(temp!=root)//匹配结束控制   
  93.         {  
  94.             if(temp->cnt>=0)//判断该结点是否被访问   
  95.             {  
  96.                 count+=temp->cnt;//由于cnt初始化为 0,所以只有cnt>0时才统计了单词的个数   
  97.                 temp->cnt=-1;//标记已访问过   
  98.             }  
  99.             else//结点已访问,退出循环   
  100.                 break;  
  101.             temp=temp->fail;//回溯 失败指针 继续寻找下一个满足条件的结点   
  102.         }  
  103.     }  
  104.     return count;  
  105. }  
  106. int main()  
  107. {  
  108.     int T,n;  
  109.     scanf("%d",&T);  
  110.     while(T--)  
  111.     {  
  112.         root=(struct Node *)malloc(sizeof(Node));  
  113.         Init(root);  
  114.         scanf("%d",&n);  
  115.         for(int i=0;i<n;i++)  
  116.         {  
  117.             scanf("\n%s",keyword);  
  118.             Build_trie(keyword);  
  119.         }  
  120.         Build_AC_automation(root);  
  121.         scanf("\n%s",s);  
  122.         printf("%d\n",query(root));  
  123.     }  
  124.     return 0;  
  125. }  
自己留着看的
0 0