这里有个大神的博客:http://www.cnblogs.com/yefeng1627/archive/2013/05/23/3094566.html
题意:给你一些模式串和一个文本串,求在文本串中出现次数最多的模式串,输出次数和这些模式串。
文本串很长,模式串数量多但长度短,适用于AC自动机。
第一写AC自动机,基本照着敲的,不过稍微懂了些,希望早点掌握啦。
这题直接先建一个AC自动机,把串都编号,用map来防重复,在AC自动机里用一个cnt数组记录所有串的编号的出现次数,最后遍历所有串的边号,找出最多的次数,然后在遍历所有的字符串,找出串编号出现次数等于最大值的串。
代码:
#include<iostream> #include<cstdio> #include<vector> #include<string> #include<map> #include<queue> #include<cmath> #include<algorithm> #include<cstring> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 10005 #define INF 0xfffffff #define mem(a,b) memset(a,b,sizeof(a)) #define FOR(i,s,t) for(int i=s;i<=t;i++) #define ull unsigned long long #define ll long long #define N 20000 #define M 1000006 using namespace std; struct AC { int ch[N][26],f[N],last[N]; int val[N],cnt[N]; int top; void init()//基本都得置0 { top=0; memset(ch,0,sizeof(ch)); memset(f,0,sizeof(f)); memset(last,0,sizeof(last)); memset(val,0,sizeof(val)); memset(cnt,0,sizeof(cnt)); } int NewNode() { int x=++top; return x; } void insert(char *s,int num)//传参串的编号,类似trie的构建 { int l=strlen(s); int p=0; for(int i=0; i<l; i++) { int c=s[i]-'a'; if(ch[p][c]==0) { ch[p][c]=NewNode(); } p=ch[p][c]; } val[p]=num; } void getfail()//求每个结点的f数组和last数组,分别表示失配指针和失配的模式串指针 { queue<int> q; for(int c=0; c<26; c++)//初始化所有只有一个字符的节点的失配指针都指向树根 { int u=ch[0][c]; if(u) { f[u]=0; last[u]=0; q.push(u); } } while(!q.empty()) { int r=q.front(); q.pop(); for(int c=0; c<26; c++) { int u=ch[r][c]; if(!u)//如果r没有c这个子孙,那么就连到与r的失配指针指向的节点的c子孙 { ch[r][c]=ch[f[r]][c]; continue; } q.push(u);//如果该节点存在,更新f和last数组 int v=f[r]; while(v&&!ch[v][c]) v=f[v];//更新f f[u]=ch[v][c]; last[u]=val[f[u]]?f[u]:last[f[u]];//更新last } } } void find(char *s) { int n=strlen(s); int p=0; for(int i=0; i<n; i++) { int c=s[i]-'a'; p=ch[p][c];//这里直接匹配,可能匹配成功,也可能失败 if(val[p]) count(p);//如果匹配成功,并且有这个串,就计数 else if(last[p])//如果改点不是模式串,那就看他的失配指针 { count(last[p]); } } } void count(int x) { if(x)//如果改点是模式串就计数,并且把有相同后记的所有节点递归计数 { cnt[val[x]]++; if(last[x]) { count(last[x]); } } } } ac; map<char*,int> mp; char text[M]; char str[155][77]; int main() { int n; while(scanf("%d",&n)==1) { if(!n) break; mp.clear(); ac.init(); int tot=0; for(int i=1; i<=n; i++) { scanf("%s",str[i]); if(mp.count(str[i])==0) mp[str[i]]=++tot; ac.insert(str[i],mp[str[i]]); } ac.getfail(); scanf("%s",text); ac.find(text); int k=0; for(int i=1; i<=tot; i++) { k=max(k,ac.cnt[i]); } printf("%d\n",k); for(int i=1; i<=n; i++) { if(ac.cnt[mp[str[i]]]==k) { printf("%s\n",str[i]); } } } return 0; }