任务描述
现在,搜索引擎已经走进了每个人的生活,比如,大家使用Google
、百度,等等。 Wiskey
希望将搜索引擎引入到他的图像检索系统中。 每个图像都有一个很长的文字描述,当用户键入一些关键字来查找图像时,系统会将关键字与图像的文字描述进行匹配,并显示出匹配关键字最多的图像。 本题要求,给出一个图像的文字描述和一些关键字,请您计算有多少个关键字匹配。
编程要求
根据提示,在右侧编辑器补充代码。
测试说明
输入说明
输入的第一行给出一个整数,表示有多少个测试用例。 每个测试用例首先给出整数N
,表示关键字的数目;然后给出N
个关键字(N<=10000
),每个关键字只包含从'a'
到'z'
的字符,长度不超过50
。 最后一行是图像的文字描述,长度不超过1000000
。
输出说明
输出给出在描述中包含了多少个关键字。
平台会对你编写的代码进行测试:
测试输入:
1
5
she
he
say
shr
her
yasherhs
预期输出: 3
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e7+5;
const int MAX=10000000;
int cnt;
struct node{ //节点的结构类型
node *next[26]; //序数值为i的子节点为next[i]
node *fail; //匹配指针
int sum; //匹配的模式数
};
node *root; //根
char key[70]; //关键字
node *q[MAX]; //队列
int head,tail; //队列的首位指针
node *newnode; //辅助节点
char pattern[maxn]; //图像的文字描述
int N; //关键字的数目
void Insert(char *s) //将关键字s插入Trie树
{
node *p=root; //从根出发
for(int i=0;s[i];i++) //依次插入每个字符
{
int x=s[i]-'a'; //计算第i个字符的序数值
if(p->next[x]==NULL) //若p不存在序数值为x的子节点,则构造next[]域、sum域和fail域全0的子节点newnode,并将其设为p的序数值为x的子节点
{
newnode=(struct node*)malloc(sizeof(struct node));
for(int j=0;j<26;j++)newnode->next[j]=0;
newnode->sum=0;newnode->fail=0;
p->next[x]=newnode;
}
p=p->next[x]; //从p的序数值为x的子节点继续搜索下去
}
p->sum++; //关键字的数目+1
}
void build_fail_pointer() //设置Trie树的fail指针
{
head=0; //队列的首尾指针初始化
tail=1;
q[head]=root; //根入队
node *p; //辅助节点p和temp
node *temp;
while(head<tail) //若队列非空,则队首节点temp出队
{
temp=q[head++];
for(int i=0;i<=25;i++) //枚举每个字母的序数值
{
if(temp->next[i]) //若temp存在序数值为i的子节点
{
if(temp==root) //若temp为根,则序数值为i的子节点的fail指针指向根
{
temp->next[i]->fail=root;
}
else //在temp为中间节点情况下,从temp出发,沿fail指针一直搜索至当前节点存在序数值为i的子节点
{
p=temp->fail;
while(p)
{
if(p->next[i]) //若当前p节点存在序数值为i的子节点,则temp的序数值为i的子节点的fail指针指向p的序数值为i的子节点
{
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail; //沿p的fail指针继续搜索下去
}
if(p==NULL)temp->next[i]->fail=root; //若沿途没有任一节点存在序数值为i的子节点,则temp的序数值为i的子节点的fail指向根
}
q[tail++]=temp->next[i]; //temp的序数值为i的子节点入队
}
}
}
}
void ac_automation(char *ch) //对图像文字描述进行多关键字匹配
{
node *p=root; //从根出发
int len=strlen(ch); //计算图像文字描述的长度
for(int i=0;i<len;i++) //依次匹配每个字符
{
int x=ch[i]-'a'; //计算第i个字符的序数值x
while(!p->next[x]&&p!=root)p=p->fail; //沿fail指针搜索下去,直至当前节点p存在序数值为x的子节点或者搜索至根
p=p->next[x]; //将p的序数值为x的子节点设为p
if(!p)p=root; //若p不存在序数值为x的子节点,则根设为序数值为x的子节点
node *temp=p; //从序数值为x的子节点出发,继续沿fail指针搜索,直至搜索至根或者当前节点的sum域值为-1为止
while(temp!=root)
{
if(temp->sum>=0) //若当前节点的sum域值不小于0,则sum域值累计计入匹配的关键字数,当前节点的sum域值设为-1,以避免重复计算
{
cnt+=temp->sum;
temp->sum=-1;
}
else break; //当前节点的sum域值为-1,退出循环
temp=temp->fail; //继续沿fail指针搜索
}
}
}
int main()
{
int T;
scanf("%d",&T); //输入测试用例数
while(T--) //依次处理每个测试用例
{ //构造next[]域、fail域和sum域全0的根节点root
root=(struct node*)malloc(sizeof(struct node));
for(int j=0;j<26;j++)root->next[j]=0;
root->fail=0;
root->sum=0;
scanf("%d",&N); //读关键字数
getchar();
for(int i=1;i<=N;i++) //依次读入每个关键字,构造Trie树
{
cin>>key; //读第i个关键字
Insert(key); //将该关键字插入Trie树
}
cin>>pattern; //读图像的文字描述
cnt=0; //图像的文字描述中含关键字的数目初始化
build_fail_pointer(); //设置Trie的树的fail指针
ac_automation(pattern); //对图像文字描述进行多关键字匹配
printf("%d\n",cnt); //输出图像文字描述中内含关键字的数目
}
}