洛谷P3808 & P3796 AC自動機模板

題目:P3808:https://www.luogu.org/problemnew/show/P3808html

P3796:https://www.luogu.org/problemnew/show/P3796ios

從這裏學了下AC自動機:http://www.cnblogs.com/cjyyb/p/7196308.htmlui

個人理解大概就是構建一棵由模式串組成的 Trie 樹,而後把文本串一節一節放在上面查找;spa

失配指針指向的是結尾字母和本身同樣的、Trie 樹上的其餘分支,大約就是在找後綴這樣的感受;指針

因此文本串每加入一個字符,就在 Trie 樹上查找以這個字符結尾的後綴模式串,因此能找到全部出現過的;code

慕名已久的AC自動機原來也挺簡單的嘛!htm

代碼以下:blog

P3808:ci

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int const maxn=1e6+5;
int n,cnt;
queue<int>q;
struct N{
    int fail,son[26],end;
}AC[maxn];
void build(string s)
{
    int l=s.length();
    int nw=0;
    for(int i=0;i<l;i++)
    {
        if(AC[nw].son[s[i]-'a']==0)AC[nw].son[s[i]-'a']=++cnt;
        nw=AC[nw].son[s[i]-'a'];
    }
    AC[nw].end++;
}
void get_fail()
{
    AC[0].fail=0;
    for(int i=0;i<26;i++)
    {
        if(AC[0].son[i]==0)continue;
        AC[AC[0].son[i]].fail=0;
        q.push(AC[0].son[i]);
    }
    while(q.size())
    {
        int x=q.front(); q.pop();
        for(int i=0;i<26;i++)
        {
            if(AC[x].son[i])
            {
                AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i];
                q.push(AC[x].son[i]);
            }
            else AC[x].son[i]=AC[AC[x].fail].son[i];
        }
    }
}
int query(string s)
{
    int l=s.length();
    int ret=0,nw=0;
    for(int i=0;i<l;i++)
    {
        nw=AC[nw].son[s[i]-'a'];
        for(int t=nw;t&&AC[t].end!=-1;t=AC[t].fail)
        {
            ret+=AC[t].end;
            AC[t].end=-1;
        }
    }
    return ret;
}
int main()
{
    scanf("%d",&n);
    string s;
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        build(s);
    }
    get_fail();
    cin>>s;
    printf("%d\n",query(s));
    return 0;
}

P3796:get

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const maxn=1e6+5;
int n,cnt;
queue<int>q;
string s[155];
struct N{
    int son[26],fail,end;
}AC[maxn];
struct P{int num,pos;}ans[155];
bool cmp(P x,P y)
{
    if(x.num==y.num)return x.pos<y.pos;
    else return x.num>y.num;
}
void clear(int x)
{
    memset(AC[x].son,0,sizeof AC[x].son);
    AC[x].fail=0; AC[x].end=0;
}
void build(string s,int num)
{
    int l=s.length();
    int nw=0;
    for(int i=0;i<l;i++)
    {
        if(!AC[nw].son[s[i]-'a'])AC[nw].son[s[i]-'a']=++cnt,clear(cnt);
        nw=AC[nw].son[s[i]-'a'];
    }
    AC[nw].end=num;
}
void get_fail()
{
    while(q.size())q.pop();
    AC[0].fail=0;
    for(int i=0;i<26;i++)
    {
        if(AC[0].son[i]==0)continue;
        AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]);
    }
    while(q.size())
    {
        int x=q.front(); q.pop();
        for(int i=0;i<26;i++)
        {
            if(AC[x].son[i])
            {
                AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i];
                q.push(AC[x].son[i]);
            }
            else AC[x].son[i]=AC[AC[x].fail].son[i];
        }
    }
}
void query(string s)
{
    int l=s.length();
    int nw=0;
    for(int i=0;i<l;i++)
    {
        nw=AC[nw].son[s[i]-'a'];
        for(int t=nw;t/*&&t.end!=-1*/;t=AC[t].fail)
        {
            ans[AC[t].end].num++;
//            AC[t].end=-1;
        }
    }
}
int main()
{
    while(1)
    {
        scanf("%d",&n);
        if(!n)return 0;
        cnt=0; clear(0);
        for(int i=1;i<=n;i++)
        {
            cin>>s[i];
            build(s[i],i);
            ans[i].pos=i;
            ans[i].num=0;//
        }
        get_fail();
        cin>>s[0];
        query(s[0]);
        sort(ans+1,ans+n+1,cmp);
        printf("%d\n",ans[1].num);
        cout<<s[ans[1].pos]<<endl;
        for(int i=2;i<=n;i++)
        {
            if(ans[i].num==ans[i-1].num)
                cout<<s[ans[i].pos]<<endl;
            else break;
        }
    }
}
相關文章
相關標籤/搜索