hdu5880 ac自动机模板

旧巷老猫 提交于 2019-12-02 02:45:09

 

ac自动机:

给你若干个单词,判断一段文字里边这些单词出现了吗,在哪出现,出现几次?

 

首先是字典树模板:

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
const int maxn=1e3+50;
struct trie_node{
    int count;
    trie_node*son[26];
};
trie_node* new_node()
{
    trie_node* pnode=new trie_node();
    pnode->count=0;
    for(int i=0;i<26;i++)pnode->son[i]=NULL;
    return pnode;
}
void trie_insert(trie_node *root,char key[])
{
    trie_node* node=root;
    char *p=key;
    while(*p)
    {
        if(node->son[*p-'a']==NULL)node->son[*p-'a']=new_node();
        node=node->son[*p-'a'];
        ++p;
    }
    node->count+=1;
}
int trie_search(trie_node *root,char key[])
{
    trie_node*node=root;
    char *p=key;
    while(*p&&node!=NULL)
    {
        node=node->son[*p-'a'];
        ++p;
    }
    if(node==NULL)return 0;
    else return node->count;
}

int main()
{
    int n,q,i,j;
    char s[20];
    trie_node *root;
    root=new_node();
    scanf("%d%d",&n,&q);
    while(n--)
    {
        scanf("%s",s);
        trie_insert(root,s);
    }
    while(q--)
    {
        scanf("%s",s);
        printf("%d\n",trie_search(root,s));
    }
}
View Code

然后是ac自动机:字典树+fail指针 重点在getfail函数

 

例题是 hdu5880

 

一整天,一直被卡MLE,改成指针形式的动态开点也卡。

然后去搜,终于搜到一篇博客。

博客说:不要一次性memset,而是,用到一个点,memset一次。

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define debug printf("!");
using namespace std;
const int maxn=1e6+5;
struct T{
    int fail;
    int vis[26];
    int dep;
}ac[maxn];

int cnt;

char s[maxn];

void init(int t)
{
    ac[t].fail=ac[t].dep=0;
    memset(ac[t].vis,0,sizeof(ac[t].vis));
}


inline void insert(char *s)
{
    int len=strlen(s),i,p=0,dep=0;
    for(i=0;i<len;i++)
    {
        dep++;
        if(!ac[p].vis[s[i]-'a'])
        {
            ac[p].vis[s[i]-'a']=++cnt;
            init(cnt);
        }
        p=ac[p].vis[s[i]-'a'];
    }
    ac[p].dep=dep;
}
inline void get_fail()
{
    queue<int>que;
    for(int i=0;i<26;i++)
    {
        if(ac[0].vis[i])
        {
            ac[ac[0].vis[i]].fail=0;
            que.push(ac[0].vis[i]);
        }
    }
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=0;i<26;i++)
        {
            if(ac[u].vis[i]!=0)
            {
                ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];
                que.push(ac[u].vis[i]);
            }
            else ac[u].vis[i]=ac[ac[u].fail].vis[i];
        }
    }
}
void query(char s[])
{
    int len=strlen(s),i,j,k,t=0,p=0;
    for(i=0;i<len;i++)
    {
        char c=s[i];
        if('A'<=c&&c<='Z')c+=32;
        else if(!('a'<=c&&c<='z'))
        {
            p=0;continue;
        }
        p=ac[p].vis[c-'a'];
        for(j=p;j;j=ac[j].fail)
        {
            if(ac[j].dep)
            {
                for(k=i-ac[j].dep+1;k<=i;k++)s[k]='*';
            }
        }
    }
}
int main()
{
    int n,T;
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;
        init(0);
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",s);
            insert(s);
        }
        get_fail();
        getchar();
        cin.getline(s,maxn);
        query(s);
        printf("%s\n",s);
    }
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!