zoukankan      html  css  js  c++  java
  • HDOJ 2222 Keywords Search

    Accepted 2222 593MS 30816K 2430 B G++

    第一道 AC 自动机,理解了就好写;

    需要注意字典可能重复,重复的不能按一次算。

    # include <cstdio>
    # include <cstring>
    # include <queue>
    
    using namespace std;
    
    # define WORD_LEN 50 + 5
    # define MAXN 10000 + 5
    # define ALPHA_SIZE 26
    
    int n, id;
    char t[1000000 + 10];
    char w[MAXN][WORD_LEN];
    
    struct node
    {
        node * fail;
        node * next[ALPHA_SIZE];
        int id;
        int isEnd;        // 字典里有重复的单词 
        node ()
        {
            fail = NULL;
            memset(next, 0, sizeof(next));
            id = 0;
            isEnd = 0;
        }
    }* root;
    
    
    int alpha_map(char ch)
    {
        return ch - 'a';
    }
    
    void insert_trie(node * root, char *s)
    {
        int c, i;
        node * p = root;
        for (i = 0; s[i]; ++i)
        {
            c = alpha_map(s[i]);
            if (NULL == p->next[c]) p->next[c] = new node;
            p = p->next[c];
        }
        ++(p->isEnd);
    }
    
    void build_trie(node * root)
    {
        for (int i = 0; i < n; ++i)
            insert_trie(root, w[i]);
    }
    
    void build_AC_auto(node *root)
    {
        int i;
        node *cur, *tmp;
        queue <node *> Q;
    
        // 根节点的子节点单独处理
        Q.push(root);
        for (i = 0; i < ALPHA_SIZE; ++i)
        {
            if (root->next[i])
            {
                root->next[i]->fail = root;
                Q.push(root->next[i]);
            }
        }Q.pop();    // 根节点出队
    
        // 更新非根节点子节点的 fail
        while (!Q.empty())
        {
            cur = Q.front(); Q.pop();    // 当前节点出队
            for (i = 0; i < ALPHA_SIZE; ++i)
            {
                if (cur->next[i])
                {
                    tmp = cur->fail;            // 找到当前节点的 fail
                    // 更新子节点的 fail
                    while (tmp)
                    {
                        if (tmp->next[i])
                        {
                            cur->next[i]->fail = tmp->next[i];
                            break;
                        }
                        tmp = tmp->fail;
                    }
                    // 没有找到可以匹配的
                    if (NULL == tmp)
                    {
                        cur->next[i]->fail = root;
                    }
                    // 将子节点入队
                    Q.push(cur->next[i]);
                }
            }
        }
    }
    
    int search(char *t, node * root)
    {
        int i, c, ret = 0;
        node *tmp, *p = root;
    
        for (i = 0; t[i]; ++i)
        {
            c = alpha_map(t[i]);
            while (root != p && NULL == p->next[c]) p = p->fail;
            p = p->next[c];
            if (NULL == p) p = root;
            tmp = p;
            while (tmp)
            {
                if (tmp->isEnd)
                {
                    ret += tmp->isEnd;
                    tmp->isEnd = 0;
                }
                tmp = tmp->fail;
            }
        }
    
        return ret;
    }
    
    void init(void)
    {
        id = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%s", w[i]);
        scanf("%s", t);
    }
    
    void solve(void)
    {
        root = new node;
        build_trie(root);
        build_AC_auto(root);
        printf("%d\n", search(t, root));
    }
    
    int main()
    {
        int T;
    
        scanf("%d", &T);
        while (T--)
        {
            init();
            solve();
        }
    
        return 0;
    }

    /**/

  • 相关阅读:
    文本框改造之多选下拉控件
    多附件上传控件
    Linq to Sql:更新之属性遍历法
    如何在HTML5页面中启动本地的App? 下面的方法应该可以。
    Nodejs 学习笔记-相片整理Demo(二)
    Nodejs 学习笔记-相片整理Demo(一)
    前端学习笔记一:什么是W3C?
    网页嵌入调用 全国各城市天气代码
    html页面清除缓存
    判断鼠标动作,可以给鼠标在标签不同区域的动作分别写不同的效果
  • 原文地址:https://www.cnblogs.com/JMDWQ/p/2618037.html
Copyright © 2011-2022 走看看