zoukankan      html  css  js  c++  java
  • AC自动机习题(一本通)

    1479:【例题1】Keywords Search

    这个也是模板题

    注意开的数据范围,重点是看getfail函数和que函数的写法(记住呀)

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1e4+10;
    const int M=1e6+10;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    //AC自动机模板题
    char s[M];
    int ch[maxn*32][26];
    int fail[maxn*32],flag[maxn*32];
    int t,n,tot=0;
    void inti(){
    	memset(ch,0,sizeof(ch));
    	memset(flag,0,sizeof(flag));
    	memset(fail,0,sizeof(fail));
    	tot=0;
    }
    void inse(string s){
    	int now=0;
    	for(int i=0;i<s.length();i++){
    		int x=s[i]-'a';
    		if(!ch[now][x]){
    			ch[now][x]=++tot;
    		}
    		now=ch[now][x];
    	}
    	flag[now]++; //这里单词数+1 
    }
    void getfail(){
    	queue<int> q;
    	for(int i=0;i<26;i++){
    		if(ch[0][i]) {
    			fail[ch[0][i]]=0;
    			q.push(ch[0][i]);
    		}
    	} 
    	while(!q.empty()){
    		int op=q.front();
    		q.pop();
    		for(int i=0;i<26;i++){
    			if(ch[op][i]){
    				fail[ch[op][i]]=ch[fail[op]][i];
    				q.push(ch[op][i]);
    			}
    			else ch[op][i]=ch[fail[op]][i];
    		}
    	}
    }
    int que(string s){
    	int now=0,ans=0;
    	for(int i=0;i<s.size();i++){
    		now=ch[now][s[i]-'a'];
    		for(int j=now;j&&flag[j]!=-1;j=fail[j]){
    			ans+=flag[j];
    			flag[j]=-1;
    		}
    	}
    	return ans;
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		inti();
    		scanf("%d",&n);
    		string tmp;
    		for(int i=0;i<n;i++){
    			cin>>tmp;
    			inse(tmp);
    		}
    		fail[0]=0;
    		getfail();
    		scanf("%s",s);
    		printf("%d
    ",que(s));
    			
    	}
    return 0;
    }
    

      

    1480:玄武密码

    我们只需要先建立所有密码的trie树
    再以母串为主串跑一个AC自动机
    不过其中还是有一些需要改动的地方
    原本字典树中用来记录某个节点是不是字符串结尾的数组不需要,直接删去
    我们需要另一个数组来标记哪些点被匹配
    跑完ac自动机后从trie树上找最后一个匹配的点即可
    优化:由于nxt数组是递归到0的所以只要有一个点被标记过,那么这个点到0的所有点都已经被遍历过直接退出即可
    //为什么一个点超时啊。。。。

    有的说是SAM好做一些,还不会先留着

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1e7+10;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    /*
    我们只需要先建立所有密码的trie树
    再以母串为主串跑一个AC自动机
    不过其中还是有一些需要改动的地方
    原本字典树中用来记录某个节点是不是字符串结尾的数组不需要,直接删去
    我们需要另一个数组来标记哪些点被匹配
    跑完ac自动机后从trie树上找最后一个匹配的点即可
    优化:由于nxt数组是递归到0的所以只要有一个点被标记过,那么这个点到0的所有点都已经被遍历过直接退出即可
    */
    //为什么一个点超时啊。。。。 
    int ch[maxn][4];
    int fail[maxn];
    int flag[maxn];
    int n,m,tot=0;
    char ss[maxn];
    char sa[100050][150];
    int jud(char x){
    	if(x=='E') return 0;
    	else if(x=='S') return 1;
    	else if(x=='W') return 2;
    	else if(x=='N') return 3;
    }
    void inse(string s){
    	int now=0;
    	for(int i=0;i<s.length();i++){
    		int x=jud(s[i]);
    		if(!ch[now][x]){
    			ch[now][x]=++tot;
    		}
    		now=ch[now][x];
    	}  //flag不用加了,因为是用来判断有没有访问过的 
    }
    void getfail(){
    	queue<int> q;
    	for(int i=0;i<4;i++) {
    		if(ch[0][i]) q.push(ch[0][i]);
    	}
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=0;i<4;i++){
    			if(ch[u][i]) fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]);
    			else ch[u][i]=ch[fail[u]][i];
    		}
    	}
    }
    void biaoji(string s){
    	int u=0;
    	for(int i=0;i<s.length();i++){
    		int c=jud(s[i]);
    		u=ch[u][c];
    		for(int j=u;j;j=fail[j]){
    			if(flag[j]) break;
    			flag[j]=1;
    		}
    	}
    }
    int getan(string s){
    	int u=0,ans=0;
    	for(int i=0;i<s.length();i++){
    		int c=jud(s[i]);
    		u=ch[u][c];
    		if(flag[u]) ans=i+1;
    	}
    	return ans;
    }
    int main(){
    	scanf("%d %d",&n,&m);
    	scanf("%s",ss);
    	for(int i=0;i<m;i++){
    		scanf("%s",sa[i]);
    		inse(sa[i]);
    	}
    	getfail();
    	biaoji(ss);
    	for(int i=0;i<m;i++){
    		printf("%d
    ",getan(sa[i]));
    	}
    return 0;
    }
    

      

  • 相关阅读:
    作业29——制作首页的显示列表。
    作业28——发布功能完成。
    作业27——登录之后更新导航
    作业26——完成登录功能,用session记住用户名
    作业25——完成注册功能
    作业24——通过用户模型,对数据库进行增删改查操作。
    作业23——连接mysql数据库,创建用户模型
    作业22——管理信息系统的开发与管理
    作业——21加载静态文件,父模板的继承和扩展
    值类型与引用类型区别
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/12732669.html
Copyright © 2011-2022 走看看