• 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("
    %s",keyword);
    118             Build_trie(keyword);
    119         }
    120         Build_AC_automation(root);
    121         scanf("
    %s",s);
    122         printf("%d
    ",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

  • 相关阅读:
    SuperMemo UX 添加笔记 Ctrl+H
    SuperMemo概念初识(摘录)
    win7安装office2013过程中出现 office 15 click-to-run extensibility component提示
    Automactically loading LSP files
    droppable的详细参数讲解
    PHP定时执行任务的实现
    随机数的妙用
    cursor的形状
    ajax防止重复提交请求1
    使用JS截取字符串函数详解
  • 原文地址:https://www.cnblogs.com/weixq351/p/9485749.html
Copyright © 2020-2023  润新知