UVA11019 Matrix Matcher (二维AC自动机)

题目:https://vjudge.net/problem/UVA-11019

题意:
给一个 n*m大矩阵,一个 x*y小矩阵;
求小矩阵在大矩阵中出现次数。

分析:
将小矩阵按行插入Trie树中;
结尾标记val为行号;
注意有可能多行对应一个节点,因此val应为vector;
find()大矩阵中每行,若出现匹配,则标记这次匹配对应的小矩阵右上角出现的位置;
若一个位置被标记次数>=x,则为一次成功匹配。

代码:

#include 
using namespace std;
typedef long long ll;
const int tmax=1e4+5;
int n,m,x,y,num;
int ch[tmax*30][30],f[tmax*30],last[tmax*30],cnt[1005][1005];
char mat[1005][1005];
vector<int> val[tmax*30];
queue<int> Q;
void insert(char *s,int line)
{
    int i,id,u=0,len=strlen(s);
    for(i=0;i'a';
        if(!ch[u][id]) ch[u][id]=++num;
        u=ch[u][id];
    }
    val[u].push_back(line);
    return;
}
void getfail()
{
    int i,x,u,v;
    Q.push(0);
    while(!Q.empty())
    {
        x=Q.front();
        Q.pop();
        for(i=0;i<26;i++)
        {
            u=ch[x][i];
            if(!u)
            {
                ch[x][i]=ch[f[x]][i];
                continue;
            }
            Q.push(u);
            if(x==0) continue;
            v=f[x];
            while(v&&!ch[v][i]) v=f[v];
            f[u]=ch[v][i];
            if(val[f[u]].size()==0) last[u]=last[f[u]];
            else last[u]=f[u];
        }
    }
    return;
}
void find(char *s,int line)
{
    int i,u=0,j,k,len=strlen(s+1),id;
    for(i=1;i<=len;i++)
    {
        id=s[i]-'a';
        u=ch[u][id];
        j=u;
        do{
            for(k=0;kif(line-val[j][k]+1>=1)
                    cnt[line-val[j][k]+1][i]++;
            j=last[j];
        }while(j);
    }
    return;
}
int main()
{
    int T,i,j;
    char tmp[105];
    cin>>T;
    while(T--)
    {
        for(i=1;i<=num;i++) val[i].clear();
        num=0;
        memset(ch,0,sizeof(ch));
        memset(f,0,sizeof(f));
        memset(last,0,sizeof(last));
        memset(cnt,0,sizeof(cnt));
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            scanf("%s",&mat[i][1]);
        scanf("%d%d",&x,&y);
        for(i=1;i<=x;i++)
        {
            scanf("%s",tmp);
            insert(tmp,i);
        }
        getfail();
        for(i=1;i<=n;i++)
            find(mat[i],i);
        int ans=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(cnt[i][j]>=x) ans++;
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(字符串,AC自动机)