这里有个大神的博客: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;
}