• HDU-2222-Keywords Search(AC自动机)


    这题是AC自动机的模板题,AC自动机是结合了字典树,和KMP两种算法产生的,去年为了学习AC自动机去看了前面说的两种算法,但是可能因为KMP当时理解的不够透彻所以这题当时也只是半背代码的做出来了,没多久就忘了。经过那么久的学习感觉KMP掌握的差不多了,今天回顾了一下AC自动机,并记录一下模板

    • AC自动机
      Accepted 2222 327MS 56848K 1991 B G++
      #include "cstdio"
      #include "cstring"
      #include "cstdlib"
      #include "queue"
      using namespace std;
      const int MAXS = 1000005;
      const int MAXP = 55;
      const int SIZE = 26;
      struct Tree {
          int tail;
          Tree* next[SIZE];
          Tree* fail;
      }* root;
      char p[MAXP], s[MAXS];
      Tree* init() {
          Tree* point = (Tree*)malloc(sizeof(Tree));
          point->tail = 0;
          memset(point->next, NULL, sizeof(point->next));
          point->fail = NULL;
          return point;
      }
      void insert(char* p) {
          Tree* point = root;
          for (int i = 0; p[i]; i++) {
              int index = p[i] - 'a';
              if (point->next[index] == NULL) {
                  point->next[index] = init();
              }
              point = point->next[index];
          }
          point->tail++;
      }
      void build() {
          queue<Tree*> q;
          Tree* point;
          Tree* p1;
          Tree* p2;
          q.push(root);
          while (!q.empty()) {
              point = q.front();
              q.pop();
              for (int i = 0; i < SIZE; i++) {
                  if (point->next[i] != NULL) {
                      p1 = point->fail;
                      p2 = point->next[i];
                      while (p1 != NULL) {
                          if (p1->next[i] != NULL) {
                              p2->fail = p1->next[i];
                              break;
                          }
                          p1 = p1->fail;
                      }
                      if (p1 == NULL) {
                          p2->fail = root;
                      }
                      q.push(p2);
                  }
              }
          }
      }
      int query(char* s) {
          int cnt = 0;
          Tree* p1;
          Tree* p2;
          p1 = root; 
          for (int i = 0; s[i]; i++) {
              int index = s[i] - 'a';
              while (p1 != root && p1->next[index] == NULL) {
                  p1 = p1->fail;
              }
              p1 = p1->next[index];
              if (p1 == NULL) {
                  p1 = root;
              }
              p2 = p1;
              while (p2 != root && p2->tail != -1) {
                  cnt += p2->tail;
                  p2->tail = -1;
                  p2 = p2->fail;
              }
          }
          return cnt;
      }
      void clear(Tree* point) {
          for (int i = 0; i < SIZE; i++) {
              if (point->next[i] != NULL) {
                  clear(point->next[i]);
              }
          }
          free(point);
      }
      int main() {
          int t, n;
          scanf("%d", &t);
          while (t--) {
              root = init();
              scanf("%d", &n);
              while (n--) {
                  scanf("%s", p);
                  insert(p);
              }
              scanf("%s", s);
              build();
              printf("%d
      ", query(s));
              clear(root);
              root = NULL;
          }
          return 0;
      } 

      build的时候网上的代码都是用自己写的队列,我一开始用自己写的队列运行时间达到了171ms,确实比库里封装的快不少,但是我还是喜欢用库里的比较保险。弄懂了KMP和字典树看一下网上的讲解就好理解了。

  • 相关阅读:
    c# 得到 XML的节点值和属性值
    jquery 更改超链接
    row_number()得到中间的信息
    UML系统分析与设计03-软件需求分析说明书
    UML系统分析与设计02-用例图和活动图(下)
    从Klocwork中.net检测项说说代码书写
    WCF之诡异通讯超时
    《Beginning WF : Windows Workflow in .NET 4.0》读书笔记
    UML系统分析与设计01-准备
    UML系统分析与设计02-用例图和活动图(上)
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/10358416.html
Copyright © 2020-2023  润新知