zoukankan      html  css  js  c++  java
  • 洛谷P3808 【模板】AC自动机(简单版) AC自动机

    网址:https://www.luogu.org/problem/P3808

    题意:

    给定$n$个模式串和$1$个文本串,求有多少个模式串在文本串里出现过,相同的模式串需要多次计算。

    题解:

    $AC$自动机的模板题。$AC$自动机是基于$Trie$树的有限状态自动机,又称$Trie$图,$AC$自动机的结点的$fail$指针构造方法如下:在$Trie$树上,类似于$KMP$的$fail$指针,对于非空结点,找到其父亲的$fail$指针对应的结点的相同字母的儿子结点。对于空节点,直接把它连到其父亲的$fail$指针对应的结点的相同字母的儿子结点,根结点的儿子的$fail$指针指向根,形成转移图。然后查询的时候,我们要求的是求出现次数,所以我们当到达一个结点的时候,我们可以跳$fail$指针匹配其后缀,然后匹配过的加上标记防止重新匹配。

    #include <iostream>
    #include <string>
    #include <queue>
    using namespace std;
    #define maxn int(2e6+5)
    int trie[maxn][26];
    int cntword[maxn];
    int fail[maxn];
    int cnt = 0;
    struct ac
    {
    	void insert(string& str)//插入字符串
    	{
    		int root = 0, next;
    		for (int i = 0; i < str.size(); ++i)
    		{
    			next = str[i] - 'a';
    			if (!trie[root][next])
    				trie[root][next] = ++cnt;//将字符的位置按照放入顺序递增
    			root = trie[root][next];
    		}
    		++cntword[root];//该位置单词结束
    	}
    	void buildfail()
    	{
    		queue<int>que;
    		for (int i = 0; i < 26; ++i)
    		{
    			if (trie[0][i])
    			{
    				fail[trie[0][i]] = 0;//根的儿子的fail一定指向根
    				que.push(trie[0][i]);//将其放入队列
    			}
    		}
    		while (!que.empty())
    		{
    			int now = que.front();//出队,以其为根
    			que.pop();
    			for (int i = 0; i < 26; ++i)
    			{
    				if (trie[now][i])
    				{
    					fail[trie[now][i]] = trie[fail[now]][i];//fail指向其父节点的fail对应的相同子节点
    					que.push(trie[now][i]);
    				}
    				else
    					trie[now][i] = trie[fail[now]][i];//空节点是其父节点对应fail的相同儿子
    			}
    		}
    	}
    	int query(string& str)
    	{
    		int now = 0, ans = 0;
    		for (int i = 0; i < str.size(); ++i)
    		{
    			now = trie[now][str[i] - 'a'];
    			for (int j = now; j && cntword[j] != -1; j = fail[j])//匹配根到当前结点的子串的后缀以节省时间
    			{
    				ans += cntword[j];
    				cntword[j] = -1;
    			}
    		}
    		return ans;
    	}
    };
    int main()
    {
    	string tmp;
    	ios::sync_with_stdio(0);
    	cin.tie(0);
    	ac AC;
    	int n;
    	cin >> n;
    	for (int i = 0; i < n; ++i)
    	{
    		cin >> tmp;
    		AC.insert(tmp);
    	}
    	fail[0] = 0;
    	cin >> tmp;
    	AC.buildfail();
    	cout << AC.query(tmp) << endl;
    	return 0;
    }
    

      

    AC代码:

  • 相关阅读:
    HTML入门(HB、DW)
    HTML入门(HB、DW)
    数据库流行度6月排行榜:Oracle飙升MySQL止跌回升
    The 'mode' option has not been set, webpack will fallback to 'production' for th is value
    Error: Cannot find module 'webpack/schemas/WebpackOptions.json'
    seafile python api requests
    Linux上复制tomcat启动需要注意的问题
    SQL优化:你真的知道国家字符集的性能影响吗?
    OpenCV3.4.1+VS2017安装教程(WINDOWS10)
    HTML入门(HB、DW)
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11559806.html
Copyright © 2011-2022 走看看