分析:
给出N个子串建树,再给出M个母串来查询每个母串含有哪几个子串。还是一只自动AC机~题解:
直接套用AC自动机模板,不过需要修改几个地方:
建树:
void insert(char *s)
{
Node * t = root;
for(;*s;s++)
{
int x = *s ;
if(t -> ch[x] == NULL)
t -> ch[x] = newNode();
t = t -> ch[x];
}
t -> match = loc++;//开一个全局变量loc存储病毒的编号,每存储一个病毒,编号递增一下。
}
匹配:
bool run(char *s) //判断每个网站有没有含病毒,并记录病毒编号
{
CLR(ans);
bool flag = false;
Node * t = root;
for(; *s ; s++)
{
int x = *s ;
t = t->ch[x];
for(Node*u = t; u->match != -1;u = u->fail)
{
if(u->match>0)//match大于0表示匹配完成了一个病毒
{
int tmp = u->match;
if(!ans[tmp]) //如果ans数组里没有存储该病毒
{
ans[tmp] = 1;//存储病毒
cnt++; //该网站含病毒数++
}
flag = true; //表示该网站含有病毒
}
}
}
return flag;
}
- AC代码:
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
int loc;
int cnt;
const int k = 128;
const int MAXN = 60010;
int ans[MAXN];
struct Node
{
Node* ch[k], *fail;
int match;
void clear()
{
memset(this, 0, sizeof(Node));
}
};
Node * que[MAXN];
struct ACAutomaton
{
Node nodes[MAXN], *root, *superRoot, *cur; //全局变量
Node * newNode() //从内存池中初始化一个结点
{
cur -> clear();
return cur++;
}
void clear() //清空整个字典树
{
cur = nodes;
superRoot = newNode();
root = newNode();
root -> fail = superRoot;
for(int i=0;i<k;i++) //superRoot为虚拟的超级根结点,所有孩子均指向实际的根结点,减少建立自动机的代码量
superRoot -> ch[i] = root;
superRoot->match = -1;
}
void insert(char *s)
{
Node * t = root;
for(;*s;s++)
{
int x = *s ;
if(t -> ch[x] == NULL)
t -> ch[x] = newNode();
t = t -> ch[x];
}
t -> match = loc++;
}
void build() //使用自动机前,要先生成失配指针
{
int p=0, q =0;
que[q++] = root;
while(p!=q) //BFS求失配指针
{
Node*t = que[p++];
for(int i=0;i<k;i++)
{
if(t->ch[i])
{
t -> ch[i] -> fail = t->fail ->ch[i];
que[q++] = t->ch[i];
}else
t->ch[i] = t -> fail ->ch[i];
}
}
}
bool run(char *s) //在自动机上与匹配串s进行匹配
{
CLR(ans);
bool flag = false;
Node * t = root;
for(; *s ; s++)
{
int x = *s ;
t = t->ch[x];
for(Node*u = t; u->match != -1;u = u->fail)
{
if(u->match>0)
{
int tmp = u->match;
if(!ans[tmp])
{
ans[tmp] = 1;
cnt++;
}
flag = true;
}
//u -> match = -1;
}
}
return flag;
}
};
int n;
ACAutomaton j;
char s[20000];
int main()
{
int N,M;
while(~scanf("%d", &N))
{
j.clear();
loc = 1;
int n = N;
while(n--)
{
scanf("%s", s);
j.insert(s);
}
j.build();
scanf("%d", &M);
int total = 0;
int i =1;
while(M--)
{
cnt = 0;
scanf("%s", s);
bool flag = j.run(s);
if(flag)
{
//cout << cnt << endl;
sort(ans, ans+cnt);
total++;
printf("web %d: ", i);
for(int j=1;j<=N;j++)
{
if(ans[j] == 1)
{
cout << j;
cnt--;
if(cnt) cout << " ";
else
{
cout << endl;
break;
}
}
}
}
i++;
}
printf("total: %d\n", total);
}
return 0;
}