• HDU3065【AC自动机-AC感言】


    Fourth AC zi dong ji(Aho-Corasick Automation) of life

    9A(其实不止交了10发...) 感言:
    一开始多组数据这种小数据还是...无伤大局,因为改完以后还是wa...

    一:

    最后发现是wa在构造fail指针的时候在建立临时指针查询有没有匹配到的fail,在没有匹配到的时候,结点的fail的指针要指向根。

    二(重要感言):
    在查询时,往上回溯fail指针的时候,fail指针是一定会最终回溯到根的,而且,比如当前查询到的主串是ABCDEF,fail指针可能会一直传递最终到根,但是并不是都有效啊!这里还要注意,fail指针传递过去,找到的是子串,还是本来那个串的后缀串,为什么说是子串:如果有模式串ABCD,ABCDEF,主串是ACBDEF,主串到D的时候已经处理掉了ABCD,这个情况下是不会用到fail指针的功效了,或者这里没有有效的后缀串;什么时候会用fail指针呢,如果有模式串CD,BCD,ABCDEF,主串是ACBDEF,那么在主串到D的时候会通过fail指针找到BCD,然后在找到CD,所以我们能得出,fail指针的回溯,当前串(比如ABCD)最后那个D是一直不会变的,可以说fail指针都是D的fail指针!
    三:
    不要依赖模板...

    推荐几个数据:

    2
    CC
    AAA
    ooxxCC%dAAAoen....ENDooxxCC%dAAAoen....ENDooxxCC%dAAAoen....END

    2
    ABCDE
    BCD
    ABCD

    2
    ABCDE
    BCD
    ABCDEF

    //#include <bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    
    /*
    题意:
    求不同的病毒出现的次数,未出现的不需要输出
    AAA其中AA出现2次;
    思路:
    那我存的应该是编号了,编号都不同。
    */
    
    const int N=5e4+10;
    
    struct Trie
    {
        int id;
        Trie *next[26],*fail;
    };
    Trie q[N],*root;
    int tol,ans[1010],n;
    char ss[1010][51];
    
    Trie* Creat()
    {
        Trie *p;
        p=&q[tol++];
        p->fail=NULL;
        p->id=0;
        for(int i=0; i<26; i++)
            p->next[i]=NULL;
        return p;
    }
    
    void Insert(char *str,int id)
    {
        Trie *p=root;
        int index,len=strlen(str);
        for(int i=0; i<len; i++)
        {
            index=str[i]-'A';
            if(p->next[index]==NULL)
                p->next[index]=Creat();
            p=p->next[index];
        }
        p->id=id;
    }
    
    void Build_Ac()
    {
        queue<Trie*>que;
        que.push(root);
        while(!que.empty())
        {
            Trie *p=que.front();que.pop();
            for(int i=0; i<26; i++)
            {
                if(p->next[i]!=NULL)
                {
                    if(p==root)
                        p->next[i]->fail=root;
                    else
                    {
                        Trie *temp=p->fail;
                        while(temp!=NULL)//找匹配的
                        {
                            if(temp->next[i]!=NULL) //找到
                            {
                                p->next[i]->fail=temp->next[i];
                                break;
                            }
                            temp=temp->fail;
                        }
                        if(temp==NULL)  //如果没有找到匹配的,则fail指向根
                        	p->next[i]->fail=root;
                    }
                    que.push(p->next[i]);
                }
            }
        }
    }
    
    char word[2000010];
    void Query()
    {
        int res=0;
        int index,len=strlen(word);
        Trie *p=root;
    
        for(int i=0; i<len; i++)
        {
            if(!(word[i]>='A'&&word[i]<='Z')){
                p=root;
                continue;
            }
            index=word[i]-'A';
            while(p->next[index]==NULL && p!=root)
                p=p->fail;
            p=p->next[index];
            if(p==NULL)
                p=root;
            Trie *temp=p;
            while(temp!=root)   //回溯到根
            {
                ans[temp->id]++;    //这里这样写没事,因为我不会用到id为0的,任他+
                temp=temp->fail;
            }
        }
        for(int i=1; i<=n; i++)
        {
            if(ans[i])
                printf("%s: %d
    ",ss[i],ans[i]);
        }
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            tol=0;
            root=Creat();
            for(int i=1; i<=n; i++)
            {
                ans[i]=0;
                scanf("%s",ss[i]);
                Insert(ss[i],i);
            }
            getchar();
            Build_Ac();
            gets(word);
            Query();
        }
        return 0;
    }
    


  • 相关阅读:
    基于Python实现的死链接自动化检测工具
    MySQL 慢查询日志配置与简析
    Git 常用命令及操作总结
    redis redis常用命令及内存分析总结(附RedisClient工具简介
    Jenkins Jenkins结合GIT Maven持续集成环境配置
    JAVA TestNG单元测试详解
    MyEclipse TestNG插件安装与配置
    JAVA 利用MyEclipse结合TestNG测试框架进行单元测试
    lintcode :前序遍历和中序遍历树构造二叉树
    lintcode: 中序遍历和后序遍历树构造二叉树
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777432.html
Copyright © 2020-2023  润新知