码迷,mamicode.com
首页 > 其他好文 > 详细

AC自动机模板题

时间:2020-03-11 00:50:10      阅读:49      评论:0      收藏:0      [点我收藏+]

标签:建图   重复   code   trie   end   i++   mes   sizeof   模板   

P3808 AC自动机(简单版)

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e6+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
void Insert(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    sum[rt]++;
}
void get_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
int query(string s)
{
    int rt=0,ans=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        for(int k=rt;k&&sum[k]!=-1;k=fail[k])
            ans+=sum[k],sum[k]=-1;
    }
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    string s;
    for(int i=1;i<=n;i++)
        cin>>s,Insert(s);
    get_fail();
    cin>>s;
    printf("%d\n",query(s));
    return 0;
}

P3796 AC自动机(加强版)

有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e4+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
int ans[maxx];
string s[maxx];
void Insert(string s,int x)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    sum[rt]=x;
}
void get_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
void query(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        for(int k=rt;k;k=fail[k])ans[sum[k]]++;
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        tot=0;
        memset(trie,0,sizeof(trie));
        memset(sum,0,sizeof(sum));
        memset(fail,0,sizeof(fail));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++)
            cin>>s[i],Insert(s[i],i);
        get_fail();
        string t;
        cin>>t;
        query(t);
        int tmp=0;
        for(int i=1;i<=n;i++)tmp=max(tmp,ans[i]);
        printf("%d\n",tmp);
        for(int i=1;i<=n;i++)
            if(ans[i]==tmp)cout<<s[i]<<endl;
    }
    return 0;
}

P5357 AC自动机(二次加强版)

给你一个文本串 S 和 n 个模式串 T1...Tn,请你分别求出每个模式串Ti 在 S 中出现的次数。

拓扑建图优化

#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e5+10;
int trie[maxx][26],tot;
int fail[maxx],vis[maxx];
int in[maxx],ma[maxx],sum[maxx],ans[maxx];
void Insert(string s,int x)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    if(!vis[rt])vis[rt]=x;
    ma[x]=vis[rt]; //重复单词
}
void getfail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])
            {
                fail[trie[u][i]]=trie[fail[u]][i];
                in[fail[trie[u][i]]]++;
                q.push(trie[u][i]);
            }
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
void query(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        sum[rt]++;
    }
}
void topu()
{
    queue<int>q;
    for(int i=0;i<=tot;i++)
        if(in[i]==0)q.push(i);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        ans[vis[u]]=sum[u];
        int v=fail[u];
        in[v]--;
        sum[v]+=sum[u];
        if(in[v]==0)q.push(v);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    string s;
    for(int i=1;i<=n;i++)
        cin>>s,Insert(s,i);
    getfail();
    cin>>s;
    query(s);
    topu();
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[ma[i]]);
    return 0;
}

AC自动机模板题

标签:建图   重复   code   trie   end   i++   mes   sizeof   模板   

原文地址:https://www.cnblogs.com/HooYing/p/12459784.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!