zoukankan      html  css  js  c++  java
  • ●小集训之旅 一

    有多大的思想,才有多大的能量。

      • 2017.3.27
        1. 学习内容:Aho-Corasick automaton(AC自动机)(原来不是自动AC机…)
        2. 算法用途:多模板串的模式匹配问题。
        3. 算法步骤:
          1. 用模板串构造Trie树(字典树 or 前缀树);
          2. 用bfs在Trie树中构建失配指针fail;
          3. 模式匹配(文本串和模板串进行匹配)
        4. HDU2222 Keywords Search(本题即为模版…)
          1. 一个裸题(入门练手用)(但要注意细节,不然要像我一样调两三节课,555)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<queue>
    #define N 500010 
    using namespace std;
    int trie[N][27],f[N],last[N],val[N],n,cnt,ans;
    char T[2*N],P[55];
    void make(int x)                            //求答案,与刘汝佳的print()相似 
    {
    	if(!x)return; 
    	if(val[x]) ans+=val[x],val[x]=0;             
    	make(last[x]);
    }
    void add_trie(char *P)                      //模板串加入Trie树 
    {
        int x=0,i=0;char ch;
        while(P[i])
    	{
            ch=P[i]-'a';
            if(!trie[x][ch])trie[x][ch]=++cnt;       
            x=trie[x][ch]; i++;
        }
        val[x]++;                               //有重复模板串 
    }
    void getfail()                              //bfs求fail[](and last[]) 
    {
        queue<int> q; int rt,u,v;
        for(int i=0;i<26;i++) 
        if(trie[0][i]) q.push(trie[0][i]),f[trie[0][i]]=last[trie[0][i]]=0;
        while(!q.empty())
        {
            rt=q.front(); q.pop();
            for(int i=0;i<26;i++)
            {
                u=trie[rt][i]; 
                if(!u)continue; q.push(u);v=f[rt];
                while(v&&!trie[v][i])v=f[v];
                f[u]=trie[v][i];
                last[u]=val[f[u]]?f[u]:last[f[u]];
            }
        }
    }
    void Aho_Corasick_automaton(char *T)              //匹配 
    {
        int x=0,ch;
        for(int i=0;T[i];i++)
        {
            ch=T[i]-'a';
            while(x&&!trie[x][ch])x=f[x];
            x=trie[x][ch];
            if(val[x]) make(x);
            else if(last[x]) make(last[x]);
        }
    }
    int main()
    {
        int cas;scanf("%d",&cas);while(cas--) 
        {	
            memset(trie,0,sizeof(trie));              
            memset(val,0,sizeof(val));
            scanf("%d",&n); ans=0;cnt=0;  
            for(int i=1;i<=n;i++) scanf("%s",P), add_trie(P);
            getfail();                                     
            scanf("%s",T);
            Aho_Corasick_automaton(T);
            printf("%d
    ",ans);
        }
        return 0;
    }
    /*	对于多组数据 : 
    	trie[],val[] 必须memset
      	f[],last[] 不必memset,
      	因为(在bfs求fail值时)每个点的f和last值来源于之前的点
     	所以只需在往队列里加初值时,把对应的点的f和last赋值为0就行了 */
          1. 如汝佳所言(《训练指南》P216):“把所有不存在的边补上,即把计算失配函数中的语句 if(!u)continue; 改为 if(!u){trie[rt][i]=trie[f[rt]][i];continue;};这样while()便可直接删去。”  
          2. (个人认为原理同求last是一致的,与bfs的先进先出的特点有关) 改后的代码如下: 
    void getfail()                              
    {
        queue<int> q; int rt,u,v;
        for(int i=0;i<26;i++) 
        if(trie[0][i]) q.push(trie[0][i]),f[trie[0][i]]=last[trie[0][i]]=0;
        while(!q.empty())
        {
            rt=q.front(); q.pop();
            for(int i=0;i<26;i++)
            {
                u=trie[rt][i]; 
                if(!u){trie[rt][i]=trie[f[rt]][i];continue;};    //**
    			q.push(u);v=f[rt];
                f[u]=trie[v][i];
                last[u]=val[f[u]]?f[u]:last[f[u]];
            }
        }
    }
    void Aho_Corasick_automaton(char *T)              
    {
        int x=0,ch;
        for(int i=0;T[i];i++)
        {
            ch=T[i]-'a';
            x=trie[x][ch];
            if(val[x]) make(x);                                 //**
            else if(last[x]) make(last[x]);
        }
    }


    Do not go gentle into that good night.
    Rage, rage against the dying of the light.
    ————Dylan Thomas
  • 相关阅读:
    如何实现进程间的通信
    调试手记
    WinCE的一些忠告——UNICODE编码
    一道字符串复制的面试题目
    strcpy和strncpy区别
    关于#include头文件问题
    rs232串口通讯中,读串口与读端口的区别
    IP包过滤(转)
    小数点后截位问题
    一些函数
  • 原文地址:https://www.cnblogs.com/zj75211/p/6632111.html
Copyright © 2011-2022 走看看