• P3796 【模板】AC自动机(加强版)


    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <algorithm>
    #include <vector>
    using namespace std;
    struct Trie	{
    	int fail;
    	int son[26];
    	int end;
    } AC[1000005];
    struct Str {
    	int num, pos;
    } str[1000005];
    bool cmp(Str a, Str b) {
    	if(a.num != b.num) return a.num > b.num;
    	else return a.pos < b.pos;
    }
    int cnt = 0;
    void Clean(int x) {
    	AC[x].fail = AC[x].end = 0;
    	memset(AC[x].son, 0, sizeof(AC[x].son));
    }
    inline void Build(string s, int num) { //把模式串依次插入trie
    	int l = s.length();
    	int now = 0;
    	for(int i = 0; i < l; i++) {
    		if(AC[now].son[s[i] - 'a'] == 0) {
    			AC[now].son[s[i] - 'a'] = ++cnt;
    			Clean(cnt);//不初始化的话会mle,因为这是一个新的结点
    		}
    		now = AC[now].son[s[i] - 'a'];
    	}
    	AC[now].end = num;//以now为结尾的字符串在输入里的序号为num
    }
    void getFail() { //计算失配指针
    	queue<int> q;
    	for(int i = 0; i < 26; i++) { //单独处理第二层的失配指针
    		if(AC[0].son[i] != 0) { //根结点的这个儿子存在的话
    			AC[AC[0].son[i]].fail = 0;//因为比它深度更浅的只有根结点了
    			q.push(AC[0].son[i]);//入队准备进行BFS
    		}
    	}
    	while(!q.empty()) {
    		int u = q.front();
    		q.pop();
    		for(int i = 0; i < 26; i++) {//找当前结点的所有子结点,因为是BFS,所以上一层所有结点的fail指针都已经计算出来了,满足计算当前结点fail指针的条件
    			if(AC[u].son[i] != 0) {//如果这个子结点存在的话
    				AC[AC[u].son[i]].fail = AC[AC[u].fail].son[i];//当前结点子结点的失配指针设置为当前结点的fail指针指向的结点的所有子结点中和当前结点子结点值相同的结点
    				q.push(AC[u].son[i]);//入队
    			} else {
    				AC[u].son[i] = AC[AC[u].fail].son[i];//当前结点的子结点不存在,就把这个子结点设置为当前结点失配指针指向的结点的所有子结点中和当前结点子结点值相同的结点
    				//相当于走到了当前结点发现无路可走,就退而求其次,看看跳到从根到当前结点这个串的最长后缀的最后面能不能继续走下去
    				//注意此时当前结点fail指针指向的结点由于深度更浅,它的son[i]已经被更浅层的结点更新过了,所以可以拿过来用
    				//考虑这么一棵trie:0-1-2-3  0-2-3  0-3-4
    			}
    		}
    	}
    }
    void AC_Query(string s) { //对文本串进行匹配
    	int l = s.length();
    	int now  = 0;//一开始从树根 开始遍历
    	for(int i = 0; i < l; i++) {
    		now = AC[now].son[s[i] - 'a'];//这里的now遍历过的字符串路径实际上就是文本串
    		for(int t = now; t; t = AC[t].fail) {//直接将t指向失配指针以节约时间
    			str[AC[t].end].num++;//AC[t].end这个编号对应的字符串数目++
    		}
    	}
    }
    int main() {
    	freopen("data.txt", "r", stdin);
    	std::ios::sync_with_stdio(false);
    	cin.tie(0); 
    	cout.tie(0);
    	int n;
    	while(cin >> n && n) {
    		cnt = 0;
    		Clean(0);
    		vector<string> v;
    		v.push_back(" ");
    		for(int i = 1; i <= n; i++) {
    			string s;
    			cin >> s;
    			str[i].pos = i;
    			str[i].num = 0;//出现次数
    			Build(s, i);
    			v.push_back(s);
    		}
    		AC[0].fail = 0;
    		getFail();
    		string t;
    		cin >> t;
    		AC_Query(t);
    		sort(str + 1, str + n + 1, cmp);
    		int times = str[1].num;
    		cout << times << endl;
    		for(int i = 1; i <= n; i++) {
    			if(str[i].num == times) {
    				cout << v[str[i].pos] << endl;
    			} else {
    				break;
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    创建ROS工程結構
    ubuntu下boot分区空间不足问题的解决方案
    Ubuntu下查看自己的GPU型号
    win+Ubuntu双系统安装和卸载、Ubuntu上OpenCV+ROS环境配置
    Opencv——摄像头设置
    error:Assertion failed ((unsigned)i0 < (unsigned)size.p[0]) in cv::Mat::at
    error: OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in cv::Mat::Mat
    常用的传感器和运动机构
    步进电机与伺服电机
    Opencv——级联分类器(AdaBoost)
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14491237.html
Copyright © 2020-2023  润新知