UVA-11019Matrix Matcher(AC自动机)

本文介绍了一种使用AC自动机解决文本串中模板串出现次数的问题,通过构建Trie树并采用特定算法进行匹配,提供了完整的代码示例。同时提及了另一种基于Hash的方法,可以在更短的时间内完成任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目的大意是对于给定的文本串和模板串,要求出模板串在文本串中出现的次数,那么很显然可以先对模板串一行一行的进行构建Trie树,而后对于文本串也一行一行的进行匹配寻找,在寻找的过程中对相应的行列进行记录就可以了,其中要注意的是模板串中可能重复字符串,即不同行的字符串相同,因而要另设一数组进行相应的记录,妥妥的一道AC自动机题。


值得一提的是本题可以用Hash的思想去做,并且时间复杂度可以降到50ms(AC自动机的时间复杂度达到2000+ms),但其构造过程比较奇特,博主自己的Hash也不是很会- -.....有兴趣得可以到VJUDGE上搜索题目后看LeaderBoad,代码是公开的。


下面是AC自动机的代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
char ax[1005][1005],ac[105][105];
int cnt[1005][1005],N,M,X,Y;
const int maxn=105*105;
int Next[maxn][27],fail[maxn],value[maxn],last[maxn],My[maxn];
struct Trie
{
    int L,root;
    int getNewnode()
    {
        for(int i=0;i<26;i++)
            Next[L][i]=0;
        value[L++]=0;
        return L-1;
    }
    void init()
    {
        memset(cnt,0,sizeof(cnt));
        memset(My,0,sizeof(My));
        L=0;
        root=getNewnode();
        return ;
    }
      void Insert(char* s,int id)
    {
        int p=root;
        int len=strlen(s);
        for(int i=0;i<len;i++)
        {
            int ad=s[i]-'a';
            if(Next[p][ad]==0)
                Next[p][ad]=getNewnode();
            p=Next[p][ad];
        }
        if(value[p])
           My[id+1]=value[p];
        value[p]=id+1;
    }
    void build()
    {
       fail[root]=root;
       queue<int> q;
       for(int i=0;i<26;i++)
       {
           int u=Next[0][i];
           if(u)
           {
               fail[u]=0;
               last[u]=0;
               q.push(u);
           }
       }
       while(!q.empty())
       {
          int p=q.front();
          q.pop();
          for(int i=0;i<26;i++)
            {
                int temp=Next[p][i];
                if(!temp)
                {
                    Next[p][i]=Next[fail[p]][i];
                    continue;
                }
                q.push(temp);
                int v=fail[p];
                while(v&&!Next[v][i])
                    v=fail[v];
                fail[temp]=Next[v][i];
                last[temp]=value[fail[temp]]?fail[temp]:last[fail[temp]];
            }
       }
    }
    void print(int x,int y,int j)
    {
        if(j)
        {
             if(x-value[j]+1>=0)
                cnt[x-value[j]+1][y]++;
              int t =value[j];
             while(My[t])
             {
                 t=My[t];
                 if(x-t+1>=0)
                    cnt[x-t+1][y]++;

             }
           print(x,y,last[j]);
        }
    }
    void find1(char* s,int r)
    {
      int p=root;
      int len=strlen(s);
      for(int i=0;i<len;i++)
      {
        int x=s[i]-'a';
        p=Next[p][x];
        if(value[p])
           print(r,i,p);
        else if(last[p])
            print(r,i,last[p]);
      }
    }
}AC;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int ans=0;
        AC.init();
        scanf("%d%d",&N,&M);
        for(int i=0;i<N;i++)
            scanf("%s",&ax[i]);
        scanf("%d%d",&X,&Y);
        for(int i=0;i<X;i++)
        {
            scanf("%s",&ac[i]);
            AC.Insert(ac[i],i);
        }
        AC.build();
        for(int i=0;i<N;i++)
            AC.find1(ax[i],i);
        for(int i=0;i<N;i++)
            for(int j=0;j<M;j++)
            {
                if(cnt[i][j]==X)
                    ans++;
            }
        printf("%d\n",ans);

    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值