hdu2896
题意:在文本串中找出所包含的模式串,并计数有多少文本串,具体可看
hdu2896 http://acm.hdu.edu.cn/showproblem.php?pid=2896
知道AC自动机就很好做了
推荐的学习链接:
http://acm.uestc.edu.cn/bbs/read.php?tid=4294
http://blog.csdn.net/niushuai666/article/details/7002823
最好是看刘汝佳的训练指南,感觉更好理解
代码:
//text中出现哪些模式串
#include<cstring>
#include<queue>
#include<cstdio>
#include<map>
#include<string>
#include<algorithm>
#define MT(x,i) memset(x,i,sizeof(x))
using namespace std;
queue<int>q;
int ans[5],cc;
const int MAXNODE = 500*200 +100;
struct ACA
{
int ch[MAXNODE][130];//点 ASCII码
int f[MAXNODE]; //fail数组
int val[MAXNODE]; //>0就是单词位尾节点
int last[MAXNODE]; //后缀节点
int sz; //节点总数
void init(){
sz=1; //一个根节点
MT(ch[0],0);
}
void Insert(char *s,int v){ //插入字符串。v>0
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int c=s[i];
if(!ch[u][c]){ //节点不存在
MT(ch[sz],0);
val[sz]=0;
ch[u][c]=sz++; //新建节点
}
u=ch[u][c]; //往下走
}
val[u]=v; //单词尾标记信息
}
void getFail(){
while(!q.empty())q.pop();
f[0]=0;
for(int c=0;c<128;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<128;c++){
int u=ch[r][c];
if(!u) { ch[r][c]=ch[f[r]][c]; 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]];
}
}
}
void print(int j){
if(j) ans[cc++]=val[j]; //存下j号模式串标记
}
void Find(char *T){//在text中找模板串
int n=strlen(T);
int j=0; //当前节点编号,初始为根节点
for(int i=0;i<n;i++){
int c=T[i];
j=ch[j][c];
if(val[j]) print(j);
else if(last[j]) print(last[j]);
}
}
};
ACA ac;
char bd[210],web[11000];
int main()
{
int n,m;
while(~scanf("%d",&n)){
ac.init(); int total=0;
for(int i=1;i<=n;i++){
scanf("%s",bd);
ac.Insert(bd,i);
}
ac.getFail();
scanf("%d",&m);
for(int w=1;w<=m;w++){
scanf("%s",web);
cc=0;
ac.Find(web);
if(cc>0){
total++;
printf("web %d:",w);
sort(ans,ans+cc);
for(int i=0;i<cc;i++) printf(" %d",ans[i]);
puts("");
}
}
printf("total: %d\n",total);
}
return 0;
}
hdu 3065 http://acm.hdu.edu.cn/showproblem.php?pid=3065
对每个找到的模式串计数,并没有什么不同
#include<cstring>
#include<queue>
#include<cstdio>
#include<map>
#include<string>
#include<algorithm>
#define MT(x,i) memset(x,i,sizeof(x))
using namespace std;
queue<int>q;
int cnt[1005];
const int MAXNODE = 1000*50 +100;
struct ACA
{
int ch[MAXNODE][130];//点 ASCII码
int f[MAXNODE]; //fail数组
int val[MAXNODE]; //>0就是单词位尾节点
int last[MAXNODE]; //后缀节点
int sz; //节点总数
void init(){
sz=1; //一个根节点
MT(ch[0],0);
}
void Insert(char *s,int v){ //插入字符串。v>0
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int c=s[i];
if(!ch[u][c]){ //节点不存在
MT(ch[sz],0);
val[sz]=0;
ch[u][c]=sz++; //新建节点
}
u=ch[u][c]; //往下走
}
val[u]=v; //单词尾标记信息
}
void getFail(){
while(!q.empty())q.pop();
f[0]=0;
for(int c=0;c<128;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<128;c++){
int u=ch[r][c];
if(!u) { ch[r][c]=ch[f[r]][c]; 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]];
}
}
}
void print(int j){
if(j) cnt[val[j]]++; //j号模式串计数+1
}
void Find(char *T){//在text中找模板串
int n=strlen(T);
int j=0; //当前节点编号,初始为根节点
for(int i=0;i<n;i++){
int c=T[i];
j=ch[j][c];
if(val[j]) print(j);
else if(last[j]) print(last[j]);
}
}
};
ACA ac;
char bd[1100][55],web[2100000];
int main()
{
int n,m;
while(~scanf("%d",&n)){
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",bd[i]);
ac.Insert(bd[i],i);
}
ac.getFail();
scanf("%s",web);
MT(cnt,0);
ac.Find(web);
for(int i=1;i<=n;i++){
if(cnt[i]>0)
printf("%s: %d\n",bd[i],cnt[i]);
}
}
return 0;
}
AC自动机模板:
const int SIGMA_SIZE = 26;
const int MAXNODE = 11000;
const int MAXS = 150 + 10;
map<string,int>ms;
struct AhoCorasickAutomata
{
int ch[MAXNODE][SIGMA_SIZE];
int f[MAXNODE];//fail数组
int val[MAXNODE];//val>0就是单词节点
int last[MAXNODE];//链表的下一个节点
int cnt[MAXS];
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';
}
//插入字符串。v必须非0
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;//中间节点是0
ch[u][c]=sz++;//新建节点
}
u=ch[u][c];//往下走
}
val[u]=v;//字符串最后一个字符标志信息为v
ms[string(s)]=v;
}
//递归打印以节点j结尾的所有字符串
void print(int j){
if(j){
cnt[val[j]]++;
print(last[j]);
}
}
//在T中找模板
int 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 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]];
}
}
}
};
AhoCorasickAutomata ac;
char text[1000005],P[151][80];
int n,T;
int main()
{
while(scanf("%d", &n) == 1 && n)
{
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",P[i]);
ac.Insert(P[i],i);//注意同时更新ms映射
}
ac.getFail();
scanf("%s",text);
ac.Find(text);//计算每个模板的cnt
int best = -1;
for(int i=1;i<=n;i++)
if(ac.cnt[i]>best) best=ac.cnt[i];//最大值
printf("%d\n",best);
for(int i=1;i<=n;i++)
if(ac.cnt[ms[string(P[i])]]==best) printf("%s\n",P[i]);//输出那些模板串
}
return 0;
}
一般的模板题,计数都只需要更改print函数即可