zoukankan      html  css  js  c++  java
  • 算法竞赛模板 AC自动机

    AC自动机基本操作

    (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针。

    (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思义,就是当匹配失败的时候,用于引导p指针回溯,就和KMP算法中的next数组道理相同。

    #include<bits/stdc++.h>
    using namespace std; 
    #define MAX 26     //字典树关键字为‘a’~‘b’
    char str[1000005]; //主串(文章) 
    int n;             //模式串共有n串 
    
    //字典树结点定义 
    struct Node
    {
        Node*next[MAX];
        Node*fail;
        int sum;
    }*qu[500005];
     
    void init(Node*root)
    {
        for(int i=0;i<MAX;i++)
            root->next[i]=NULL;
    }
    
    //向字典树内添加模式串 
    void Insert(Node*root,char*ch)
    {
        Node*p=root;
        while(*ch)
        {
            int index=*ch-'a'; 
            if(p->next[index]==NULL)
            {
                p->next[index]=(Node*)malloc(sizeof(Node));
                init(p->next[index]);
                p->next[index]->sum=0;
            }
            p=p->next[index];
            ch++;
        }
        p->sum++;
    }
    
    //利用模式串 字典树建树 
    Node*TrieCreate()
    {
        char ch[65];
        Node*root=(Node*)malloc(sizeof(Node));
        init(root);
        for(int i=0;i<n;i++)
        {
            scanf("%s",ch);
            Insert(root,ch);
        }
        return root;
    }
    
    //在字典树内构建 失配指针fail 
    void BuildFail(Node*root)
    {
        int head=0,tail=0,i;
        root->fail=NULL;
        qu[tail++]=root;
        while(head<tail)
        {
            Node*t=qu[head++];
            Node*p=NULL;
            for(i=0;i<26;i++)
            {
                if(t->next[i])
                {
                    if(t==root)
                        t->next[i]->fail=root;
                    else
                    {
                        p=t->fail;
                        while(p)
                        {
                            if(p->next[i])
                            {
                                t->next[i]->fail=p->next[i];
                                break;
                            }
                            p=p->fail;
                        }
                        if(!p)
                            t->next[i]->fail=root;
                    }
                    qu[tail++]=t->next[i];
                }
            }
        }
    }
    
    //AC自动机 ,返回主串中模式串的数量(文章中关键字的数量) 
    int AC(Node*root,char*str)
    {
        int len=strlen(str),cnt=0;
        Node*p=root;
        while(*str)
        {
            while(p->next[*str-'a']==NULL&&p!=root)p=p->fail;
            p=p->next[*str-'a'];
            p=(p==NULL)?root:p;
            Node*t=p;
            while(t!=root&&t->sum!=-1)
            {
                cnt+=t->sum;
                t->sum=-1;
                t=t->fail;
            }
            str++;
        }
        return cnt;
    }
    int main()
    {
        cin>>n;
        Node*root=TrieCreate();
        scanf("%s",str);
        BuildFail(root);
        printf("%d
    ",AC(root,str));
        return 0;
    }
  • 相关阅读:
    剑指offer(14)链表中倒数第K个节点
    剑指offer(13)调整数组顺序使奇数位于偶数前面
    跨域资源共享CORS
    同源政策
    剑指offer(12)数值的整数次方
    剑指offer(11)二进制中1的个数
    面试金典——交点
    LeetCode——简化路径
    LeetCode——跳跃游戏 I-II
    LeetCode——最大矩形
  • 原文地址:https://www.cnblogs.com/kannyi/p/9488004.html
Copyright © 2011-2022 走看看