AC自动机 HDU 2222

AC自动机分为三部分:

1.构造字典树

2.构找失败指针

3.匹配

解决的问题: 如给你n个单词,然后一篇问章,问你这篇文章中单词出现了多少次?

View Code
/*
程序说明:多模式串匹配的AC自动机算法
此题通过hdu 2222
自动机算法可以参考《柔性字符串匹配》里的相应章节,讲的很清楚
*/
#include <stdio.h>
#include <string.h>


const  int MAXQ = 500000+10;
const  int MAXN = 1000000+10;
const  int MAXK = 26;  //自动机里字符集的大小 
struct  TrieNode
{
    TrieNode* fail;
    TrieNode* next[MAXK];
    bool danger;   //该节点是否为某模式串的终结点 
    int  cnt;    //以该节点为终结点的模式串个数 
    TrieNode()
    {
        fail = NULL;
        memset(next, NULL, sizeof(next));
        danger = false;
        cnt = 0;
    }
}*que[MAXQ], *root;
//文本字符串
char  msg[MAXN];
int   N;
void  TrieInsert(char *s)
{
    int  i = 0;
    TrieNode *ptr = root;
    while(s[i])
    {
        int  idx = s[i]-'a';
        if(ptr->next[idx] == NULL)
            ptr->next[idx] = new TrieNode();
        ptr = ptr->next[idx];
        i++;
    }
    ptr->danger = true;
    ptr->cnt++;
}

void  Init()
{
    int  i;
    char  s[100];
    root = new TrieNode();
    scanf("%d", &N);
    for(i = 0; i < N; i++)
    {
        scanf("%s", s);
        TrieInsert(s);
    }
}

void  Build_AC_Automation()
{
    int  rear = 1, front = 0, i;
    que[0] = root;
    root->fail = NULL;
    while(rear != front)
    {
        TrieNode *cur = que[front++];
        for(i = 0; i < 26; i++)
            if(cur->next[i] != NULL)
            {
                if(cur == root)
                    cur->next[i]->fail = root;
                else
                {
                    TrieNode *ptr = cur->fail;  //改指针父亲失败指针 
                    while(ptr != NULL)
                    {
                        if(ptr->next[i] != NULL)
                        {
                            cur->next[i]->fail = ptr->next[i];
                            if(ptr->next[i]->danger == true)
                                cur->next[i]->danger = true;
                            break;
                        }
                        ptr = ptr->fail;
                    }
                    if(ptr == NULL) cur->next[i]->fail = root;
                }
                que[rear++] = cur->next[i];
            }
    }
}

int  AC_Search()
{
    int  i = 0, ans = 0;
    TrieNode *ptr = root;
    while(msg[i])
    {
        int  idx = msg[i]-'a';
        while(ptr->next[idx] == NULL && ptr != root) ptr = ptr->fail; //匹配不到就指向其失败指针 
        ptr = ptr->next[idx];
        if(ptr == NULL) ptr = root; //等于空指针也返回其失败指针 
        TrieNode *tmp = ptr;
        while(tmp != NULL && tmp->cnt != -1)
        {
            ans += tmp->cnt;
            tmp->cnt = -1;
            tmp = tmp->fail;
        }
        i++;
    }
    return  ans;
}

int  main()
{
    int  T;
    scanf("%d", &T);
    while(T--)
    {
        Init();
        Build_AC_Automation();
        //文本 
        scanf("%s", msg);
        printf("%d\n", AC_Search());
    }
    return 0;
}

转载于:https://www.cnblogs.com/tangcong/archive/2012/08/08/2627574.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值