zoukankan      html  css  js  c++  java
  • HDU 2222 Keywords Search(AC自动机模板)

    Keywords Search

    入门题,是看b站的视频入门的,网址:http://www.bilibili.com/video/av6295004/index_2.html#page=2

    【题目链接】Keywords Search

    【题目类型】AC自动机

    &题意:

    给出n个串,然后给一篇文章,问这n个串有多少个在文章里面出现过。
    trick:n个串可能有相同的,需按照不同串处理。

    &代码:
    无注释版

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    #define maxn 1000009
    #define maxtot 500009
    
    struct Aho {
    	struct state {
    		int next[26],cnt,fail;
    	} sNode[maxtot];
    	int size;
    	std::queue<int> que;
    	void Init() {
    		while(que.size()) que.pop();
    		for(int i=0; i<maxtot; i++) {
    			memset(sNode[i].next,0,sizeof(sNode[i].next));
    			sNode[i].fail=sNode[i].cnt=0;
    		}
    		size=1;
    	}
    	void Insert(char* S) {
    		int n=strlen(S),now=0;
    		for(int i=0; i<n; i++) {
    			char c=S[i];
    			if(!sNode[now].next[c-'a'])
    				sNode[now].next[c-'a']=size++;
    			now=sNode[now].next[c-'a'];
    		}
    		sNode[now].cnt++;
    	}
    
    	void Build() {
    		sNode[0].fail=-1;
    		que.push(0);
    		while(que.size()) {
    			int u=que.front(); que.pop();
    			for(int i=0; i<26; i++) if(sNode[u].next[i]) {
    					if(u==0) sNode[sNode[u].next[i]].fail=0;
    					else {
    						int v=sNode[u].fail;
    						while(v!=-1) {
    							if(sNode[v].next[i]) {
    								sNode[sNode[u].next[i]].fail=sNode[v].next[i];
    								break;
    							}
    							v=sNode[v].fail;
    						}
    						if(v==-1) sNode[sNode[u].next[i]].fail=0;
    					}
    					que.push(sNode[u].next[i]);
    				}
    		}
    	}
    
    	int Get(int u) {
    		int res=0;
    		while(u) {
    			res+=sNode[u].cnt;
    			sNode[u].cnt=0;
    			u=sNode[u].fail;
    		}
    		return res;
    	}
    
    	int March(char *S) {
    		int n=strlen(S);
    		int res=0,now=0;
    		for(int i=0; i<n; i++) {
    			char c=S[i];
    			if(sNode[now].next[c-'a'])
    				now=sNode[now].next[c-'a'];
    			else {
    				int v=sNode[now].fail;
    				while(v!=-1&&sNode[v].next[c-'a']==0) v=sNode[v].fail;
    				if(v==-1) now=0;
    				else now=sNode[v].next[c-'a'];
    			}
    			if(sNode[now].cnt) {
    				res+=Get(now);
    			}
    		}
    		return res;
    	}
    } aho;
    char S[maxn];
    int main() {
    	// freopen("1.in","r",stdin),freopen("1.out","w",stdout);
    	int T;
    	scanf("%d",&T);
    	while(T--) {
    		int N;
    		aho.Init();
    		scanf("%d",&N);
    		for(int i=0; i<N; i++) {
    			scanf("%s",S);
    			aho.Insert(S);
    		}
    		aho.Build();
    		scanf("%s",S);
    		printf("%d
    ",aho.March(S));
    	}
    	return 0;
    }
    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    #define MAX_N 1000009
    #define MAX_Tot 500009
    
    //AC自动机结构体
    struct Aho {
    	//声明节点,注意节点内存在的信息
    	struct state {
    		int next[26];
    		int fail,cnt;
    	} stateTable[MAX_Tot];
    
    	//节点数量
    	int size;
    
    	//失配指针宽搜的队列
    	std::queue<int> que;
    
    	//初始化节点内容和size
    	void init() {
    		while(que.size()) que.pop();
    		for(int i=0; i<MAX_Tot; i++) {
    			memset(stateTable[i].next,0,sizeof(stateTable[i].next));
    			stateTable[i].fail=stateTable[i].cnt=0;
    		}
    		size=1;
    	}
    
    	//插入单词
    	void insert(char *S) {
    		int n=strlen(S);
    		//now代表现在处理到哪个节点了
    		int now=0;
    		for(int i=0; i<n; i++) {
    			char c=S[i];
    			//如果这个节点没有找到路,就新开一条路
    			if(!stateTable[now].next[c-'a'])
    				stateTable[now].next[c-'a']=size++;
    			//把现在的节点赋为将要走的节点
    			now=stateTable[now].next[c-'a'];
    		}
    		//遍历完后走到结束位置,个数++(因为本题有重复模式串的情况)
    		stateTable[now].cnt++;
    	}
    
    	//构造失配指针
    	void build() {
    		stateTable[0].fail=-1;
    		que.push(0);
    		while(que.size()) {
    			int u=que.front();
    			que.pop();
    			//BFS
    			for(int i=0; i<26; i++) {
    				if(stateTable[u].next[i]) {
    					//如果是根节点,那么他的fail指向0
    					if(u==0) stateTable[stateTable[u].next[i]].fail=0;
    					//否则就一直找到最长后缀,之后再赋值儿子的fail指针
    					else {
    						int v=stateTable[u].fail;
    						while(v!=-1) {
    							if(stateTable[v].next[i]) {
    								stateTable[stateTable[u].next[i]].fail=stateTable[v].next[i];
    								break;
    							}
    							v=stateTable[v].fail;
    						}
    						//如果v还是-1,那么fail就只能指向0了
    						if(v==-1) stateTable[stateTable[u].next[i]].fail=0;
    					}
    					//最后push进去,在for里的if里push
    					que.push(stateTable[u].next[i]);
    				}
    			}
    		}
    	}
    
    	int Get(int u) {
    		int res=0;
    		while(u) {
    			res=res+stateTable[u].cnt;
    			stateTable[u].cnt=0;
    			u=stateTable[u].fail;
    		}
    		return res;
    	}
    
    	int march(char *S) {
    		int n=strlen(S);
    		int res=0,now=0;
    		for(int i=0; i<n; i++) {
    			char c=S[i];
    			//如果这条路的next可以走就走这条
    			if(stateTable[now].next[c-'a'])
    				now=stateTable[now].next[c-'a'];
    			//否则就走fail指针的路
    			else {
    				int p=stateTable[now].fail;
    				while(p!=-1&&stateTable[p].next[c-'a']==0) p=stateTable[p].fail;
    				//如果始终没找到,就回到根节点
    				if(p==-1) now=0;
    				//如果找到了,就继续忘下走
    				else now=stateTable[p].next[c-'a'];
    			}
    			if(stateTable[now].cnt) {
    				res=res+Get(now);
    			}
    		}
    		return res;
    	}
    } aho;
    
    int T;
    
    int N;
    
    char S[MAX_N];
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("1.in","r",stdin),freopen("1.out","w",stdout);
    #endif
    	scanf("%d",&T);
    	while(T--) {
    		aho.init();
    		scanf("%d",&N);
    		for(int i=0; i<N; i++) {
    			scanf("%s",S);
    			aho.insert(S);
    		}
    		aho.build();
    		scanf("%s",S);
    		printf("%d
    ", aho.march(S));
    	}
    	return 0;
    }
    
  • 相关阅读:
    用 C# 获取 IE 临时文件(转)
    vs2008打包程序需要.net3.5支持问题的解决方案
    关于使用ssh账号上外网
    元数据管理技术及发展应用现状
    一个拨号上网的批处理文件
    windows下启动和关闭oracle数据库的bat脚本
    Solaris下配置网络
    开启windows 2000 server上的远程桌面
    FileZilla客户端使用TIPs
    学习使用gvim
  • 原文地址:https://www.cnblogs.com/s1124yy/p/6398990.html
Copyright © 2011-2022 走看看