您的位置:首页 > 产品设计 > UI/UE

lightoj-1427:Substring Frequency

2013-07-27 14:37 417 查看
A string is a finite sequence of symbols that are chosen from an alphabet. In this problem you are given a string Tand n queries each with a string Pi,
where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.

Input

Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next n lines contains
a string Pi (1 ≤ |Pi| ≤ 500).

Output

For each case, print the case number in a single line first. Then for each string Pi, report the number of times it occurs as a substring of T in a single line.


Sample Input


Output for Sample Input

2
5
ababacbabc
aba
ba
ac
a
abc
3
lightoj
oj
light
lit
Case 1:
2
3
1
4
1
Case 2:
1
1
0

刚开始没看题目,用kmp做,超时,后来看了一下主题,知道要用AC算法。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <list>
using namespace std;

char t[1000002];

int** gt;
int* fail;
int* output;

int map[500];

char query[500][501];

int stateNum,maxStateNum;
int queryNum;

void generateGoto();
void generateFail();
void parse();

int main()
{
int caseNum;

maxStateNum=250;
fail=NULL;
output=(int*)malloc(sizeof(int)*maxStateNum);
gt=(int**)malloc(sizeof(int*)*maxStateNum);

for(int i=0;i<maxStateNum;++i)
gt[i]=(int*)malloc(sizeof(int)*26);

for(int i=0;i<maxStateNum;++i)
{
for(int j=0;j<26;++j)
gt[i][j]=-1;
fail[i]=-1;
output[i]=-1;
}

scanf("%d",&caseNum);

for(int i=0;i<caseNum;++i)
{
scanf("%d",&queryNum);
memset(t,0,1000002);
scanf("%s",t);
for(int j=0;j<queryNum;++j)
{
memset(query[j],0,501);
scanf("%s",query[j]);
}

stateNum=0;
generateGoto();
if(fail!=NULL)
free(fail);
fail=(int*)malloc(sizeof(int)*maxStateNum);
for(int x=0;x<maxStateNum;++x)
fail[x]=-1;
generateFail();
parse();

printf("Case %d:\n",i+1);
for(int p=0;p<queryNum;++p)
printf("%d\n",output[map[p]]);
for(int p=0;p<=stateNum;++p)
{
for(int q=0;q<26;++q)
gt[p][q]=-1;
fail[p]=output[p]=-1;
}
}
return 0;
}
void generateGoto()
{
for(int i=0;i<queryNum;++i)
{
int pos_gt=0;
for(int j=0;query[i][j]!='\0';++j)
{
if(gt[pos_gt][query[i][j]-'a']==-1)
{
gt[pos_gt][query[i][j]-'a']=++stateNum;
pos_gt=stateNum;
}
else
pos_gt=gt[pos_gt][query[i][j]-'a'];

if(stateNum==maxStateNum)
{
maxStateNum*=2;
int** tmp=(int**)malloc(sizeof(int*)*maxStateNum);
for(int x=0;x<maxStateNum;++x)
tmp[x]=(int*)malloc(sizeof(int)*26);
for(int x=0;x<stateNum;++x)
{
for(int y=0;y<26;++y)
tmp[x][y]=gt[x][y];
free(gt[x]);
}
free(gt);
for(int x=stateNum;x<maxStateNum;++x)
for(int y=0;y<26;++y)
tmp[x][y]=-1;
gt=tmp;

int* ot=(int*)malloc(sizeof(int)*maxStateNum);
for(int i=0;i<stateNum;++i)
ot[i]=output[i];
for(int i=stateNum;i<maxStateNum;++i)
ot[i]=-1;
free(output);
output=ot;
}
}

output[pos_gt]=0;
map[i]=pos_gt;
}
for(int i=0;i<26;++i)
if(gt[0][i]==-1)
gt[0][i]=0;
}


产生goto表,每次有新的模式,从起始状态开始,若存在相应的路径,则变换到该路径的状态,若没有,则创建新的状态,并转到该状态。
void generateFail()
{
int maxSizeOfQueue=500;
list<int> queue;
fail[0]=0;
for(int i=0;i<26;++i)
if(gt[0][i]!=-1&>[0][i]!=0)
{
queue.push_back(gt[0][i]);
fail[gt[0][i]]=0;
}

while(!queue.empty())
{
int currentState=queue.front();
queue.pop_front();
for(int i=0;i<26;++i)
if(gt[currentState][i]!=-1&>[currentState][i]!=0)
{
int st=fail[currentState];
while(gt[st][i]==-1)
st=fail[st];
fail[gt[currentState][i]]=gt[st][i];
queue.push_back(gt[currentState][i]);
}
}
}


从0状态开始,0状态不会失败,1状态失败总是到0。然后层次遍历,对于fail[r],查看他的前一个状态p,p和r之间有‘a’边,若fail[p]存在‘a’的边,则fail[r]=goto(fail[p],a)。若没有,则检查fail[fail[p]],直到存在.0状态不会失败,确保迭代终止。
void parse()
{
int pos_gt=0;
for(int i=0;t[i]!='\0';++i)
{
while(gt[pos_gt][t[i]-'a']==-1)
pos_gt=fail[pos_gt];
pos_gt=gt[pos_gt][t[i]-'a'];
int tgt=pos_gt;
while(tgt!=0)
{
if(output[tgt]!=-1)
++output[tgt];
tgt=fail[tgt];
}
}
}

最后遍历主串。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lightoj