我们知道KMP是单模式匹配,求一个串在母串中是否出现过。那么AC自动机就是求多模式匹配的算法,判断n个串是否在母串中出现过。
AC自动机要用到字典树和失败指针两个很关键的东西,下面来具体说一下要怎么构造。
字典树的构造应该是比较容易,一颗以root为根的树,每个节点下面有26个节点,分别代表了a-z的字母;同时还有根据题目需要的一些标志,如该节点是否是单词的结束节点的sum,记录节点到根的长度的length以及访问标志flag。
![1 建立字典树的过程
struct node{
node *next\[26\];
node *fail;//失败指针
int length;//到根节点的距离
int flag;//访问次数
};
void insert(char *s)
{
node *p=root;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int x=s\[i\]-'a';
if(p->next\[x\]==NULL)
{
newnode=(struct node*)malloc(sizeof(struct node));
for(int i=0;i<26;i++)
newnode->next\[i\]=0;
newnode->fail=0;newnode->length=p->length+1;
p->next\[x\]=newnode;
}
p=p->next\[x\];
}
}
2 构建失败指针
什么是失败指针?失败指针也就是匹配过程中无法匹配时,跳转到失败指针处看是否能够匹配下去。]![借鉴了一下同学的一个图片,可以很清楚的看到失败指针的用处](https://img-blog.csdn.net/20170821153425525?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzIyMjU3Nzk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
构建bfs的过程可以用队列的思想来做。
每次寻找父亲节点的指针处,判断此节点是否有该字母
void build_fail_point()//构建失败指针
{
int head=0,tail=1;
node *temp,*p;
q[head]=root;
while(head<tail)
{
temp=q[head++];
for(int i=0;i<=25;i++)
{
if(temp->next[i])
{
if(temp==root)
{
temp->next[i]->fail=root;
}
else
{
p=temp->fail;
while(p)
{
if(p->next[i])
{
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(p==NULL)
temp->next[i]->fail=root;
}
q[tail++]=temp->next[i];
}
}
}
}
3 检索的过程
具体的检索过程要根据题目来进行
比如说这里我们以hdu6138为例,每次检索标记处访问过的节点。
void search(char *s,int f)//标记被访问过的节点
{
node *p=root;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int x=s[i]-'a';
while(p->next[x]==NULL&&p!=root)
p=p->fail;
if(p->next[x]!=NULL)
p=p->next[x];
node *temp=p;
while(temp!=root)
{
temp->flag=f;
temp=temp->fail;
}
}
}
AC自动机
最新推荐文章于 2024-06-18 12:51:06 发布