ACM 第十四天

字符串:

1、KMP算法(模式串达到1e6)

 

模式串达到1e4直接暴力即可。

 

字符串哈希

 字符串Hash的种类还是有很多种的,不过在信息学竞赛中只会用到一种名为“BKDR Hash”的字符串Hash算法。

 

2、AC自动机

 模式串1e6,子串1e4,所求串长度很小,达到50。

 要学会AC自动机,我们必须知道什么是Trie,也就是字典树。Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串)。

要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。ac自动机其实就是一种多模匹配算法。

AC自动机算法分为3步:解题步骤:1、建立trie树 ;2、构造失败指针(fail指针);3、模式匹配过程。

 

hdu 2222 AC自动机 模板

  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 }

 

 

next数组 模板

 1 const int N = 100100;
 2 int nxt[N];
 3 char s[100100];
 4 int slen, tlen;
 5 void get_Next()
 6 {
 7     int j, k;
 8     j = 0; k = -1; nxt[0] = -1;
 9     tlen=strlen(s);
10     while(j < tlen)
11         if(k == -1 || s[j] == s[k])
12             nxt[++j] = ++k;
13         else
14             k = nxt[k];
15 
16 }

 

 

 

参考博客:https://blog.csdn.net/liu940204/article/details/51345954

 

posted @ 2018-08-16 10:21  白雪儿  Views(150)  Comments(0Edit  收藏  举报