• AC_Automata模板


    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    int ans=0;
    
    const int maxnode=1e6+7;  
    const int sigma_size=26;
    struct AC_Automata  
    {  
        int ch[maxnode][sigma_size];  
        int val[maxnode];   // 每个字符串的结尾结点都有一个非0的val  
        int f[maxnode];     // fail函数  
        int last[maxnode];  // last[i]=j表j节点表示的单词是i节点单词的后缀,且j节点是单词节点  
        int sz;  
      
        //初始化0号根节点的相关信息  
        void init()  
        {  
            sz=1;  
            memset(ch[0],0,sizeof(ch[0]));  
            val[0]=0;  
        }  
      
        void insert(char *s,int v)  
        {  
            int u=0;  
            for(int i=0; s[i]; i++)  
            {  
                int id=s[i]-'a';  
                if(ch[u][id]==0)  
                {  
                    ch[u][id]=sz;  
                    memset(ch[sz],0,sizeof(ch[sz]));  
                    val[sz++]=0;  
                }  
                u=ch[u][id];  
            }  
            val[u]+=v;  
        }  
       
        void getFail()  
        {  
            queue<int> q;  
            last[0]=f[0]=0;  
            for(int i=0; i<sigma_size; i++)  
            {  
                int u=ch[0][i];  
                if(u)  
                {  
                    f[u]=last[u]=0;  
                    q.push(u);  
                }  
            }  
      
            while(!q.empty())// 按BFS顺序计算fail  
            {  
                int r=q.front(); q.pop();  
                for(int i=0; i<sigma_size; i++)  
                {  
                    int u=ch[r][i];  
                    if(u==0)continue;  
                    q.push(u);  
      
                    int v=f[r];  //失配边尝试平行传递
                    while(v && ch[v][i]==0) v=f[v];  
                    f[u]= ch[v][i];  
                    last[u] =  val[f[u]]?f[u]:last[f[u]];  
                }  
            }  
        }  
      
        //递归打印与结点i后缀相同的前缀节点编号  
        //进入此函数前需保证val[i]>0  
        void print(int i)  
        {  
            if(i)  
            {  
    			ans+=val[i];
    			val[i]=0;			
    			print(last[i]);  
            }  
        }  
      
        void find(char *s)  
        {  
            int j=0;//j:trie树中的节点编号  
            for(int i=0; s[i]; i++)  
            {  
                int id=s[i]-'a';  
                while(j && ch[j][id]==0) j=f[j];//ch[j][id]:第j个节点的id字母子节点编号 
                j=ch[j][id];  
                if(val[j]) print(j);  
                else if(last[j]) print(last[j]);  
            }  
        }  
      
    };  
    AC_Automata ac;  
    
    const int maxn=1e6+7;
    char ori[maxn];
    char tar[maxn];
    
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		ans=0;
    		ac.init();
    		int n;
    		scanf("%d",&n);
    	
    		for(int i=1;i<=n;i++){
    			scanf("%s",tar);
    			ac.insert(tar,1);
    		}
    	
    		ac.getFail();
    		scanf("%s",ori);
    		ac.find(ori);
    		printf("%d
    ",ans);
    	}
    }

    自动机的英文念起来好中二啊,

    自动机就是trie树和kmp算法的组合,多模板匹配的首选算法

    两种快乐的算法重叠在一起,就有了自动机(

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    贴一个轻量化的板子,原题HDU3065

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn=2e6+7;
    const int maxm=55;
    const int maxnode=1010*51;
    const int sigma=128-30;
    
    int n,m;
    int vis[1010];
    char word[1010][55];
    char ori[maxn];
    
    struct automata{
    	int ch[maxnode][sigma];
    	int val[maxnode];
    	int f[maxnode];
    	int sz;
    
    	int newnode(){
    		memset(ch[sz],0,sizeof(ch[sz]));
    		f[sz]=val[sz]=0;
    		return sz++;
    	}
    
    	void init(){
    		memset(val,0,sizeof(val));
    		sz=0;
    		newnode();
    	}
    
    	void insert(char s[],int v){	
    		int u=0;
    		for(int i=0;s[i];i++){
    			int &x=ch[u][s[i]-30];
    			u=x?x:x=newnode();	
    		}
    		val[u]=v;
    	}
    
    	void build(){
    		queue<int>q;
    		q.push(0);	
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			for(int i=0;i<sigma;i++){
    				int v=ch[u][i];
    				if(!v)ch[u][i]=ch[f[u]][i];
    				else q.push(v);
    				if(u&&v)f[v]=ch[f[u]][i];
    			}
    		}
    	}
    	
    	int find(char s[]){
    		int j=0;
    		for(int i=0;s[i];i++){
    			int id=s[i]-30;
    			j=ch[j][id];
    			int tmp=j;
    			while(tmp){
    				vis[val[tmp]]++;
    				tmp=f[tmp];
    			}
    		}
    	}
    }ac;
    
    int main(){
    	while(~scanf("%d",&n)){
    		memset(vis,0,sizeof(vis));		
    		ac.init();
    		for(int i=1;i<=n;i++){
    			scanf("%s",word[i]);
    			ac.insert(word[i],i);
    		}
    		ac.build();
    
    		scanf("%s",ori);
    		ac.find(ori);
    		
    		for(int i=1;i<=n;i++){
    			if(vis[i])printf("%s: %d
    ",word[i],vis[i]);
    		}
    	}
    }


  • 相关阅读:
    取消select默认样式
    浏览器私有前缀
    兼容ie的background-size: cover;
    关于字体
    lorem 快速生成x个单词
    bash常见命令
    rgba透明的兼容处理
    JDK源码分析(10) CopyOnWriteArrayList
    JDK源码分析(9) LinkedHashMap
    JDK源码分析(8) StringBuffer & StringBuilder
  • 原文地址:https://www.cnblogs.com/Drenight/p/8611322.html
Copyright © 2020-2023  润新知