题意:给定n个字符串和一个文本串,查找哪个字符串出现的次数的最多。
析:一匹配多,很明显是AC自动机。只需要对原来的进行修改一下,就可以得到这个题的答案,
计算过程中,要更新次数,并且要映射字符串。如果用KMP肯定会超时。
代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <map> #include <string> #include <queue> using namespace std; const int maxn = 1000000 + 5; const int sigma = 26; const int maxnode = 70 * 150 + 5; map<string, int> ms; //AC自动机 struct AhoCorasickAutomata{ int cnt[155]; int ch[maxnode][sigma]; int f[maxnode];//失配函数 int val[maxnode];//每个字符串结尾都有一个非0的val int last[maxnode];//链表的下一个结点 int sz; void init(){ sz = 1; memset(ch[0], 0, sizeof(ch[0])); memset(cnt, 0, sizeof(cnt)); ms.clear(); } int idx(char c){ return c - ‘a‘; }//进行编号 //插入字符串 void insert(char *s, int v){ int u = 0, n = strlen(s); for(int i = 0; i < n; ++i){ int c = idx(s[i]); if(!ch[u][c]){ memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v; ms[s] = v; } //查找字符串 void find(char *T){ int n = strlen(T); int j = 0;// 当前结点编号,初始为根结点 for(int i = 0; i < n; ++i){ int c = idx(T[i]); while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if(val[j]) print(j); else if(last[j]) print(last[j]);//找到 } } //打印结果,也就是更新次数 void print(int j){ if(j){ ++cnt[val[j]]; print(last[j]); } } //获得失配函数 int getFail(){ queue<int> q; f[0] = 0; //初始化队列 for(int c = 0; c < sigma; ++c){ int u = ch[0][c]; if(u){ f[u] = 0; q.push(u); last[u] = 0; } } //bfs while(!q.empty()){ int r = q.front(); q.pop(); for(int c = 0; c < sigma; ++c){ int u = ch[r][c]; if(!u) continue; q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } }; AhoCorasickAutomata ac; char text[maxn], p[155][75]; int main(){ int n; while(scanf("%d", &n) == 1 && n){ ac.init(); for(int i = 1; i <= n; ++i){ scanf("%s", p[i]); ac.insert(p[i], i); } ac.getFail(); scanf("%s", text); ac.find(text); int m = -1; for(int i = 1; i <= n; ++i) m = max(m, ac.cnt[i]); printf("%d\n", m); for(int i = 1; i <= n; ++i) if(ac.cnt[ms[p[i]]] == m) printf("%s\n", p[i]); } return 0; }
时间: 2024-10-25 15:59:55