• 【模板】AC自动机(洛谷3808&洛谷3796)


    清明时节雨纷纷,省选只能当路人。
    最近在狂补算法,AC自动机还是比较难理解。找到了洛谷日报上比较容易理解的版本,才勉强理解。
    https://www.luogu.org/blog/42196/qiang-shi-tu-xie-ac-zi-dong-ji
    千万记得前置技能trie树和KMP!
    我博客里也有有关KMP的感想。(顺带安利一发
    https://www.cnblogs.com/NightRaven/p/10554401.html
    至于trie树,是个比较简单(应该)的数据结构,稍微看看就会了8(大概)(高端操作依然不会)
    ————————————————
    总之以下是洛谷上简单版的AC自动机(加强版请再往下翻翻

    #include<bits/stdc++.h>
    #define rep(i,k,n) for(int i=k;i<=n;i++)
    #define pb push_back
    using namespace std;
    const int maxn=1000005;
    queue<int> q;
    struct ac_automation
    {
    	int tr[maxn][30],cnt,fail[maxn],val[maxn];
    	void clear_ac()
    	{
    		memset(fail,0,sizeof(fail));
    		memset(val,0,sizeof(val));
    		cnt=0;
    	}
    	void add(char *s)
    	{
    		int len=strlen(s),k=0;
    		rep(i,0,len-1)
    		{
    			int c=s[i]-'a';
    			if(!tr[k][c]) tr[k][c]=++cnt;
    			k=tr[k][c];
    		}
    		val[k]++;
    	}
    	void built()
    	{
    		rep(i,0,25) if(tr[0][i]) q.push(tr[0][i]);
    		while(!q.empty())
    		{
    			int x=q.front();
    			q.pop();
    			rep(i,0,25) if(tr[x][i])
    			fail[tr[x][i]]=tr[fail[x]][i],q.push(tr[x][i]);
    			else tr[x][i]=tr[fail[x]][i];
    		}
    	}
    	int query(char *s)
    	{
    		int len=strlen(s),k=0,ans=0;
    		rep(i,0,len-1)
    		{
    			int c=s[i]-'a';
    			k=tr[k][c];
    			for(int j=k;j && val[j]!=-1;j=fail[j]) ans+=val[j],val[j]=-1;//记得看题,每个词只记一次,若多次就不用赋值为-1.
    		}
    		return ans;
    	}
    } acauto;
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	acauto.clear_ac();
    	rep(i,1,n)
    	{
    		char c[maxn];
    		scanf("%s",c);
    		acauto.add(c);
    	}
    	char p[maxn];
    	scanf("%s",p);
    	acauto.built();
    	printf("%d",acauto.query(p));
    	return 0;
    }
    

    下面是加强版

    #include<bits/stdc++.h>
    #define rep(i,k,n) for(int i=k;i<=n;i++)
    #define pb push_back
    using namespace std;
    const int maxn=1000005;
    queue<int> q; 
    char c[155][75];
    int ans[155];
    struct ac_automation
    {
    	int tr[maxn][30],cnt,fail[maxn],val[maxn];
    	void clear_ac()
    	{
    		memset(fail,0,sizeof(fail));
    		memset(val,0,sizeof(val));
    		memset(tr,0,sizeof(tr));
    		cnt=0;
    	}
    	void add(char *s,int j)
    	{
    		int len=strlen(s),k=0;
    		rep(i,0,len-1)
    		{
    			int c=s[i]-'a';
    			if(!tr[k][c]) tr[k][c]=++cnt;
    			k=tr[k][c];
    		}
    		val[k]=j;
    	}
    	void built()
    	{
    		rep(i,0,25) if(tr[0][i]) q.push(tr[0][i]),fail[tr[0][i]]=0;
    		while(!q.empty())
    		{
    			int x=q.front();
    			q.pop();
    			rep(i,0,25) if(tr[x][i])
    			fail[tr[x][i]]=tr[fail[x]][i],q.push(tr[x][i]);
    			else tr[x][i]=tr[fail[x]][i];
    		}
    	}
    	void query(char *s)
    	{
    		int len=strlen(s),k=0;
    		rep(i,0,len-1)
    		{
    			int c=s[i]-'a';
    			k=tr[k][c];
    			for(int j=k;j;j=fail[j]) ans[val[j]]++;
    		}
    	}
    } acauto;
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	while(n)
    	{
    		memset(ans,0,sizeof(ans)); 
    		acauto.clear_ac();
    		rep(i,1,n)
    		{
    			scanf("%s",c[i]);
    			acauto.add(c[i],i);
    		}
    		char p[maxn];
    		scanf("%s",p);
    		acauto.built();acauto.query(p);
    		int maxo=-1;
    		rep(i,1,n) maxo=max(maxo,ans[i]);
    		printf("%d
    ",maxo);
    		rep(i,1,n) if(ans[i]==maxo) printf("%s
    ",c[i]); 
    		scanf("%d",&n);
    	}
    	return 0;
    }
    

    最近严重意识到自己菜的真实,很多算法都不会,又有很多的忘记了,DP也菜的不行。。。最近加油吧。

  • 相关阅读:
    Pwn-level0
    Pwn-level2
    【php】php从多个数组中取出最大的值
    【算法】php计算数字k在一段数字范围出现的次数
    【算法】php计算出丑数
    【php】php常用函数代码封装(一)数组篇
    【Golang】go语言设计模式
    什么是RPC
    【php】 php获取文件路径中的文件名和文件后缀方法
    【php】php目录路径函数系列
  • 原文地址:https://www.cnblogs.com/NightRaven/p/10561412.html
Copyright © 2020-2023  润新知