AC自动机模板

  • AC自动机判母串中出现几次子串的个数(hdu2222)
#include<iostream>
#include<queue>
using namespace std;

const int maxn = 500005;
const int Max = 26;
struct Trie
{
    int next[maxn][Max];
    int fail[maxn];
    int sum[maxn];
    int L,root;
    int cnt;
    int newnode()
    {
        for (int i = 0;i < Max;i++)
            next[L][i] = -1;
        sum[L] = 0;
        fail[L] = -1;
        return L++;
    }

    void init()
    {
        L = 0;
        cnt = 0;
        root = newnode();
    }

    void insert(char s[])
    {
        int len = strlen(s);
        int p = root;
        for (int i = 0;i < len;i++)
        {
            int to = s[i] - 'a';
            if (next[p][to] == -1)
            {
                next[p][to] = newnode();
            }
            p = next[p][to];
        }
        sum[p]++;
    }

    void build_fail()
    {
        int p = root;
        queue<int>Q;
        for (int i = 0;i < Max;i++)
        {
            if (next[p][i] != -1)
            {
                fail[next[p][i]] = root;
                Q.push(next[p][i]);
            }
        }
        while (!Q.empty())
        {
            int u = Q.front();Q.pop();
            for (int i = 0;i < Max;i++)
            {
                if (next[u][i]!=-1)
                {
                    p = fail[u];
                    while (p!=-1)
                    {
                        if (next[p][i] != -1)
                        {
                            fail[next[u][i]] = next[p][i];
                            break;
                        }
                        p = fail[p];
                    }
                    if (fail[next[u][i]] == -1)
                        fail[next[u][i]] = root;
                    Q.push(next[u][i]);
                }
            }
        }
    }

    void ac_automation(char *ch)
    {
        int p = root;
        int len = strlen(ch);
        for (int i = 0;i < len;i++)
        {
            int x = ch[i] - 'a';
            while (next[p][x] == -1 && p != root)p = fail[p];
            p = next[p][x];
            if (p == -1)p = root;
            int temp = p;
            while (temp != root)
            {
                if (sum[temp] > 0)
                {
                    cnt += sum[temp];
                    sum[temp] = -1;
                }
                else break;
                temp = fail[temp];
            }
        }
    }
}ac;

char check[1000006];
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        ac.init();
        int n;
        cin >> n;
        char s[55];
        for (int i = 1;i <= n;i++)
        {
            scanf("%s", s);
            ac.insert(s);
        }
        ac.build_fail();
        scanf("%s", check);
        ac.ac_automation(check);
        cout << ac.cnt << endl;
    }
}
  • 利用fail指针来进行状态转移(2017香港区域赛J题)
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
const int MAX=2;

int G[maxn][2];
void add_edge(int u,int v,int w)
{
    G[u][w]=v;
}
struct Trie
{
    int next[maxn][MAX],fail[maxn];
    bool end[maxn];
    int L,root;
    int newnode()
    {
        for(int i=0; i<MAX; i++)
            next[L][i]=-1;
        end[L]=0;
        L++;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(char str[],int len)
    {
        int p=root;
        for(int i=0; i<len; i++)
        {
            int num=str[i]-'0';
            if(next[p][num]==-1)
            {
                next[p][num]=newnode();
            }
            p=next[p][num];
        }
        end[p]=1;
    }
    void build()
    {
        int p=root;
        queue<int>Q;
        for(int i=0; i<MAX; i++)
        {
            if(next[p][i]==-1)
                next[p][i]=root;
            else
            {
                fail[next[p][i]]=root;
                Q.push(next[p][i]);
            }
        }
        while(!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            if(end[fail[u]])end[u]=1;
            for(int i=0; i<MAX; i++)
            {
                int &v=next[u][i];
                if(v==-1)
                {
                    v=next[fail[u]][i];
                }
                else
                {
                    Q.push(v);
                    fail[v]=next[fail[u]][i];
                }
            }
        }
    }

    int in[maxn],in2[maxn];
    int inq[maxn];
    bool vis[maxn];

    void dfs1(int u)
    {
        for(int i=0;i<MAX;i++)
        {
            int v=next[u][i];
            if(end[v])continue;
            in[v]++;
            in2[v]++;
            if(in[v]==1)
                dfs1(v);
        }
    }

    bool check()
    {
        memset(in,0,sizeof(in));
        memset(inq,0,sizeof(inq));
        memset(vis,0,sizeof(vis));
        dfs1(0);
        queue<int>Q;
        if(in[0])return 1;
        Q.push(0);
        while(!Q.empty())
        {
            int u=Q.front();Q.pop();
            for(int i=0;i<MAX;i++)
            {
                int v=next[u][i];if(end[v])continue;
                vis[v]=1;
                in[v]--;

                if(!in[v])
                {
                    inq[v]=1;
                    Q.push(v);
                }
            }
        }
        for(int i=0;i<L;i++)
        {
            if(vis[i]!=inq[i])return 1;
        }
        return 0;
    }
    int dp[maxn];
    int to[maxn];
    int Max=0;
    void dfs(int u)
    {
        for(int i=0;i<MAX;i++)
        {
            int v=next[u][i];
            if(end[v])continue;
            dfs(v);
            to[u]=max(to[u],to[v]+1);
            if(dp[u]+to[v]+1==Max)
            {
                add_edge(u,v,i);
            }
        }


    }
    void solve()
    {
        if(check())
        {
            printf("-1");
            return ;
        }
        memset(dp,0,sizeof(dp));
        memset(to,0,sizeof(to));
        memset(G,-1,sizeof(G));
        queue<int>Q;
        Q.push(0);

        while(!Q.empty())
        {
            int u=Q.front();Q.pop();
            for(int i=0;i<MAX;i++)
            {
                int v=next[u][i];
                if(end[v])continue;
                in2[v]--;
                if(dp[v]<dp[u]+1)
                    dp[v]=dp[u]+1,Max=max(Max,dp[v]);
                if(!in2[v])
                    Q.push(v);
            }
        }
        dfs(0);
        int p=root;
        while(dp[p]!=Max)
        {
            if(G[p][0]!=-1)
            {
                printf("0");
                p=G[p][0];
            }
            else
            {
                printf("1");
                p=G[p][1];
            }
        }
    }
} ac;
char num[200005];
int main()
{
    int N;
    cin>>N;
    ac.init();
    for(int i=1; i<=N; i++)
    {
        scanf("%s",num);
        ac.insert(num,strlen(num));
    }
    ac.build();
    ac.solve();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值