码迷,mamicode.com
首页 > 其他好文 > 详细

HDU-2222-Keywords Search(AC自动机模板)

时间:2019-02-10 00:02:31      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:enter   --   namespace   void   封装   字典树   pid   int   tab   

这题是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\n", query(s));
            clear(root);
            root = NULL;
        }
        return 0;
    } 

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

HDU-2222-Keywords Search(AC自动机模板)

标签:enter   --   namespace   void   封装   字典树   pid   int   tab   

原文地址:https://www.cnblogs.com/Angel-Demon/p/10358416.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!