AC自动机 - 多模式串的匹配 --- HDU 3695 Computer Virus on Planet Pandora

Problem's Link

Mean: 

有n个模式串和一篇文章,统计有多少模式串在文章中出现(正反统计两次).

analyse:

好久没写AC自动机了,回顾一下AC自动机的知识。

本题在构造文章的时候需要仔细一点,其他没什么Trick,和普通AC自动机做法一样:

build Trie  --->  build Fail_Ptr ---> matching_and_count

Time complexity: O(N*L+M)

Source code: 

复制代码
/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-07-19-10.29
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;

const int M = 6000005;
class node {
public:
    bool flag;
    node *fail, *next[26];
    node() {
        flag = false;
        fail = NULL;
        memset( next, NULL, sizeof next );
    }
};
node *root;
queue<node*> q;
char s[M], str[M];

void Insert( char *str ) { // build Trie-Tree
    node *p = root;
    int i = 0, index;
    while( str[i] ) {
        index = str[i] - 'A';
        if( p->next[index] == NULL )
            p->next[index] = new node();
        p = p->next[index];
        ++i;
    }
    p->flag = true;
}

void build_ac_automation( node *root ) { // build fail ptr
    root->fail = NULL;
    while( !q.empty() ) q.pop();
    q.push( root );
    while( !q.empty() ) {
        node *temp = q.front();
        q.pop();
        node *p = NULL;
        for( int i = 0; i < 26; ++i ) {
            if( temp->next[i] != NULL ) {
                if( temp == root ) temp->next[i]->fail = root;
                else {
                    p = temp->fail;
                    while( p != NULL ) {
                        if( p->next[i] != NULL ) {
                            temp->next[i]->fail = p->next[i];
                            break;
                        }
                        p = p->fail;
                    }
                    if( p == NULL ) temp->next[i]->fail = root;
                }
                q.push( temp->next[i] );
            }
        }
    }
}


int query( node *root ) { // mathing and count
    node *p = root;
    int i = 0, ans = 0, index;
    while( str[i] ) {
        index = str[i] - 'A';
        while( p->next[index] == NULL && p != root )
            p = p->fail;
        p = p->next[index];
        if( p == NULL )
            p = root;
        node *temp = p;
        while( temp != root && temp->flag ) {
            ans++;
            temp->flag = false;
            temp = temp->fail;
        }
        i++;
    }
    return ans;
}


inline void build_str( char *s ) {
    int len = strlen( s ), cnt = -1;
    for( int i = 0; i < len; ++i ) {
        if( s[i] >= 'A' && s[i] <= 'Z' ) {
            str[++cnt] = s[i];
            continue;
        }
        if( s[i] == '[' ) {
            ++i;
            int num = 0;
            for( ; s[i] >= '0' && s[i] <= '9'; ++i ) {
                num = num * 10 + ( s[i] - '0' );
            }
            char ch = s[i];
            ++i;
            for( int j = 1; j <= num; ++j )
                str[++cnt] = ch;
        }
    }
    str[++cnt] = '\0';
}


int main() {
    ios_base::sync_with_stdio( false );
    cin.tie( 0 );
    int Cas;
    scanf( "%d", &Cas );
    while( Cas-- ) {
        root = new node();
        int n;
        scanf( "%d", &n );
        while( n-- ) {
            scanf( "%s", s );
            Insert( s );
        }
        build_ac_automation( root );
        scanf( "%s", s );
        build_str( s );
        int ans = query( root );
        strrev( str );
        ans += query( root );
        printf( "%d\n", ans );
    }
    return 0;
}
复制代码

 

posted @   北岛知寒  阅读(262)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2014-07-17 Trie数 --- 统计公共前缀
点击右上角即可分享
微信分享提示
主题色彩