题意:给一个字典,看这个字典中匹配最多次数的是哪个单词(可以有多个)。
分析:
- AC自动机就是用来解决多模式匹配问题的工具。
- 模板用的lrj的,相比HDU 2222,动态开辟字典树。用last数组统计字典。
- 统计每一个单词匹配的次数cnt[],下标唯一对应val,最后遍历一遍cnt。
#include <bits/stdc++.h> using namespace std; const int SIGMA_SIZE = 26; const int MAXNODE = 11000; const int MAXS = 150 +10; map<string,int> ms; struct Aho { int ch[MAXNODE][SIGMA_SIZE]; int f[MAXNODE]; int last[MAXNODE]; int cnt[MAXS]; int val[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[string(s)] = v; } void getFail() { queue<int> q; f[0] = 0; for(int c = 0; c < SIGMA_SIZE; c++) { int u = ch[0][c]; if(u) { f[u] = 0; q.push(u); last[u] = 0; } } while(!q.empty()) { //失配是一个宽搜的过程 int r = q.front();q.pop(); for(int c = 0; c < SIGMA_SIZE; 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]]; //last 方便统计 } } } 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]); } } }aho; int n,T; char text[1000005],P[151][80]; int main(int argc, char const *argv[]) { while(scanf("%d",&n),n) { aho.init(); for(int i=1; i <= n; i++) { scanf("%s",P[i]); aho.insert(P[i],i); } aho.getFail(); scanf("%s",text); aho.find(text); int ans = -1; for(int i=1; i <= n; i++) if(aho.cnt[i]>ans) ans = aho.cnt[i]; printf("%d\n",ans); for(int i=1; i <= n; i++) if(aho.cnt[i]==ans) printf("%s\n",P[i]); } return 0; }