zoukankan      html  css  js  c++  java
  • HDU-2222 Keywords Search

    题目大意:

    给你一个最长为1e6的字符串,再给你一个字典,问你在这个字符串里面有多少字典中国的字符串出现过。


    解题思路:

    AC自动机模板题。

    这道题目,有两个坑点。大概是两个坑点吧。

    第一个就是要被匹配的串可能会匹配字典中的字符串多次。

    第二个就是字典中的字符串可能会重复,可能会被多次匹配到。

    比如一个数据:

    1

    3

    she

    she

    she

    shesheshe

    答案是3


    第一次写AC自动机,感觉很神奇。AC自动机就利用一个失配指针各种各样转居然就能在O(n)内求出来。非常神奇啊。

    嘛因为AC自动机我也是刚学会。所以推荐两份资料:

    Aho-Corasick自动机浅析

    AC自动机算法


    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 26;
    const int maxm = 1e6 + 5;
    
    typedef struct node{
        int num;
        node *fail;
        node *ch[maxn];
        node() {
            num = 0;
            fail = NULL;
            for( int i = 0; i < maxn; ++i )
                ch[i] = NULL;
        }
    }Trie;
    
    Trie *root;
    char str[maxm], s[55];
    
    void Insert( char *s ) {
        Trie *p = root;
        for( char *c = s; *c != 0; ++c ) {
            int i = (*c) - 'a';
            if( p -> ch[i] == NULL )
                p -> ch[i] = new Trie;
            p = p -> ch[i];
            if( (*(c + 1)) == '' ) ++(p -> num);
        }
    }
    
    void buildFailPointer() {
        queue<Trie *> q;
        while( !q.empty() ) q.pop();
    
        q.push( root );
        while( !q.empty() ) {
            Trie *now = q.front(); q.pop();
            for( int i = 0; i < maxn; ++i ) {
                if( now -> ch[i] != NULL ) {
                    if( now == root ) now -> ch[i] -> fail = root;
                    else {
                        Trie *p = now -> fail;
                        while( p != NULL ) {
                            if( p -> ch[i] != NULL ) {
                                now -> ch[i] -> fail = p -> ch[i];
                                break;
                            }
                            p = p -> fail;
                        }
                        if( p == NULL ) now -> ch[i] -> fail = root;
                    }
                    q.push( now -> ch[i] );
                }
            }
        }
    }
    int AC_auto() {
        int ans = 0;
        Trie *p = root;
        for( int i = 0; str[i] != ''; ++i ) {
            int k = str[i] - 'a';
            while( p -> ch[k] == NULL && p != root  ) p = p -> fail;
            if( p -> ch[k] == NULL ) continue;
            p = p -> ch[k];
    
            Trie *t = p;
            while( t != root ) {
                if( t -> num != 0 ) {
                    ans += t -> num;
                    t -> num = 0;
                }
                t = t -> fail;
            }
        }
        return ans;
    }
    void clearTrie( Trie *p ) {
        for( int i = 0; i < maxn; ++i ) {
            if( p -> ch[i] != NULL )
                clearTrie( p -> ch[i] );
        }
        delete p;
    }
    int main() {
        ios::sync_with_stdio(false);
    
        int n, t; cin >> t;
        while( t-- ) {
            cin >> n;
            root = new Trie;
    
            for( int i = 0; i < n; ++i ) {
                cin >> s;
                Insert(s);
            }
            buildFailPointer();
            cin >> str;
            cout << AC_auto() << endl;
            clearTrie( root );
        }
        return 0;
    }


  • 相关阅读:
    Oracle 异常处理
    Oracle 游标的使用
    jdbc 连接数据库
    从0开始疫情3D地球
    从0开始疫情3D地球
    从0开始疫情3D地球
    从0开始疫情3D地球
    从0开始疫情3D地球
    从0开始疫情3D地球
    简明 ASP.NET Core 手册问题记录
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179339.html
Copyright © 2011-2022 走看看