zoukankan      html  css  js  c++  java
  • AC自动机

    http://baike.baidu.com/view/8150013.htm

    http://acm.hdu.edu.cn/showproblem.php?pid=2222

    今天看到这道题 以为是KMP 刚学完 想拿来练手 谁知写完超时。去discuss看了看 说是用AC自动机过的 今天也没什么安排 就去了解了下 它是建立在KMP和trie树基础上的一种高效串匹配的算法

    先将字符串建成一个字典树 标记每个字符串的尾部 建完之后 输入待匹配的字符串 这是只对这个字符串进行循环查找即可 判断每个字符是否是在字典树里出现 当循环到一个字符串的尾部时 num就会加上这个字符串的数量。

    看着别人的模板打了一晚上 有些地方还是模模糊糊的 不过还是学了点东西

    View Code
      1 #include<stdio.h>
      2 #include <iostream>
      3 #include<string.h>
      4 using namespace std;
      5 struct node
      6 {
      7     int count;//标记字符串的结束 和数量
      8     struct node *next[28];//指向 26个字母的子节点 最多只有26个 一个节点有26个字母域
      9     struct node *fail;//失败指针 与KMP的next函数类似
     10     node()//初始化函数 将节点的26个指针域都清空
     11     {
     12         fail = NULL;
     13         count = 0;
     14         memset(next,NULL,sizeof(next));
     15     }
     16 }*q[1000001];
     17 int tail,head;//队列的头尾
     18 char str[1000001];    
     19 void creat(char *c,struct node *root)//建立字典树
     20 {
     21     int i = 0,num;
     22     struct node *p = root;
     23     while(c[i])
     24     {
     25         num = c[i]-97;
     26         if(p->next[num]==NULL)
     27         {
     28             p->next[num] = new node;//若为空 为其创立新节点
     29         }
     30         i++;
     31         p=p->next[num];
     32     }
     33     p->count++;//到了字符串尾部 就加一
     34     
     35 }
     36 /*
     37 在字典树上构造fail指针。构造失败指针的过程概括起来就一句话:
     38 设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,
     39 他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。
     40 如果一直走到了根节点都没找到,那就把失败指针指向根节点。
     41 所以构造fail指针 需要用到BFS。 保证是按层遍历字典树。
     42 */
     43 void bfail(struct node *root)//利用队列BFS实现层遍历 来找fail指针
     44 {
     45     int i;
     46     head = 0;
     47     tail = 0;
     48     root->fail = NULL;
     49     q[tail++] = root;
     50     while(head!=tail)
     51     {
     52         struct node *temp=q[head++];
     53         struct node *p = NULL;
     54         for(i = 0; i < 26 ; i++)
     55         {
     56             if(temp->next[i]!=NULL)
     57             {
     58                 if(temp==root)
     59                     temp->next[i]->fail = root;//所有根节点的子节点都指向根节点
     60                 else
     61                 {
     62                     p = temp->fail;
     63                     while(p!=NULL)
     64                     {
     65                         if(p->next[i]!=NULL)//找到一个节点的子节点有i字母 
     66                         {
     67                             temp->next[i]->fail=p->next[i];//设为fail指针
     68                             break;
     69                         }
     70                         p=p->fail;//循环找 与kmp类似
     71                     }
     72                     if(p==NULL)
     73                         temp->next[i]->fail = root;//若为空 指向根节点
     74                 }
     75                 q[tail++] = temp->next[i];
     76             }
     77         }
     78     }
     79 }
     80 /*
     81 匹配过程分两种情况:
     82 (1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,
     83 此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
     84 (2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,
     85 匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。
     86 */
     87 int ac(struct node *root)
     88 {
     89     int i=0,k=strlen(str),d,num = 0;
     90     struct node *p = root;
     91     for(i = 0 ;i < k ; i++)
     92     {
     93         d = str[i]-97;
     94         while(p->next[d]==NULL&&p!=root)//字典树里找不到i字符 退回根节点
     95             p=p->fail;
     96         p=p->next[d];
     97         if(p==NULL)
     98             p = root;
     99         struct node *temp = p;
    100         while(temp!=root&&temp->count!=-1)
    101         {
    102             num+=temp->count;
    103             temp->count = -1;//避免重复记录
    104             temp = temp->fail;
    105         }
    106     }
    107     return num;
    108 }
    109 int main()
    110 {
    111     int i,j,n,t;
    112     char c[52];
    113     scanf("%d",&t);
    114     while(t--)
    115     {
    116         scanf("%d%*c",&n);
    117         struct node *root = new node;
    118         for(i = 1; i <= n ; i++)
    119         {
    120             gets(c);
    121             creat(c,root);
    122         }
    123         gets(str);
    124         bfail(root);
    125         printf("%d\n",ac(root));
    126     }
    127     return 0;
    128     
    129 }
  • 相关阅读:
    spring多个context:property-placeholder不生效问题
    JAVA中自定义properties文件介绍
    spring.jar是包含有完整发布的单个jar 包,spring.jar中包含除了spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环境下才会用到 spring-mock.jar来进行辅助测试,正式应用系统中是用不得这些类的。
    web.xml文件头声明各个版本参考
    Java 组件化(gradle)
    阿里开源框架-JarsLink-【JAVA的模块化开发框架】
    二gradle创建SSM项目——Hello word
    一gradle创建SSM项目——依赖包
    微信开发学习总结(二)——微信开发入门
    js函数声明的三种方式
  • 原文地址:https://www.cnblogs.com/shangyu/p/2603586.html
Copyright © 2011-2022 走看看