UVA 11019 二维匹配 AC自动机

这个题目要求在一个大矩阵里面匹配一个小矩阵,是AC自动机的灵活应用

思路是逐行按普通AC自动机匹配,用过counts[i][j]记录一下T字符矩阵以i行j列为开头的与P等大的矩阵区域 有多少行已经匹配了,显然如果该数值==p的行数,则说明匹配成功

就是在自动机的过程中,匹配得时候要稍微多想一下,每次匹配都要调用函数对 counts进行维护,以及还要注意某些行是相同的情况,用个链表保存,匹配成功后直接链过去继续对counts进行维护

最后统计counts里面有多少个值==p的行数即可得出结果

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010;
char T[N][N];
char  word[N][N];
int x,y,n,m;
int cnt,tr;
int recline[N];
int next[N];
int len[N];
int counts[N][N];

void process_match(int pos, int v) //对counts进行维护
{
    int pr=recline[v-1];
    int c=pos-len[pr]+1;//得到矩阵行和列的数值
    while (pr>=0){
        if (tr>=pr){
            counts[tr-pr][c]++;
        }
       pr=next[pr];//直接对下一个相同的行进行该操作
    }
}
struct ACTrie
{
    int ch[N*10][30];
    int last[N*10];
    int val[N*10];
    int f[N*10];
    int sz;
    int idx(char c){
           return c-'a';
        }
    void init(){
        memset(ch,0,sizeof ch);
        memset(last,0,sizeof last);
        memset(val,0,sizeof val);
        memset(f,0,sizeof f);
        sz=1;
    }
    void insert(char*s,int v){
        int u=0;
        for (int i=0;s[i];i++){
            int c=idx(s[i]);
            if (!ch[u][c]){
               ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=v;
    }
    void getfail(){
        queue<int> q;
        for (int i=0;i<26;i++)
        {
            int u=ch[0][i];
            if (u) q.push(u);
        }
        while (!q.empty()){
            int u=q.front();
            q.pop();
            for (int i=0;i<26;i++){
                int v=ch[u][i];
                if (!v) continue;
                q.push(v);
                int p=f[u];
                while (p && !ch[p][i]) p=f[p];
                f[v]=ch[p][i];
                last[v]=val[f[v]]?f[v]:last[f[v]];
            }
        }
    }
    void report(int pos,int j){ //匹配函数要改一下,每次匹配成功都调用该函数对counts进行维护
        if (j){
            process_match(pos, val[j]);
            report(pos, last[j]);
        }
    }
    void find(char* str){
        int u=0;
        for (int i=0;str[i];i++){
            int c=idx(str[i]);
            while (u && !ch[u][c]) u=f[u];
            u=ch[u][c];
            if (val[u]){
                report(i,u);
            }
            else if (last[u])
                report(i,f[u]);
        }

    }

} ACT;
int main()
{
    int t;
    scanf("%d",&t);
    while (t--){
        scanf("%d%d",&x,&y);
        for (int i=0;i<x;i++){
            scanf("%s",T[i]);
        }
        scanf("%d%d",&n,&m);
        ACT.init();
        for (int i=0;i<n;i++){
            scanf("%s",word[i]);
            recline[i]=i;
            next[i]=-1;
            len[i] = strlen(word[i]);
            for (int j=0;j<i;j++){
                if (strcmp(word[i],word[j])==0){
                    recline[i]=j;
                    next[i]=next[j]; //用链表的方式保存相同的行
                    next[j]=i;
                    break;
                }
            }
            if (recline[i]==i){
                ACT.insert(word[i],i+1);
            }
        }
        ACT.getfail();
        memset(counts,0,sizeof counts);
        for (tr=0;tr<x;tr++){
            ACT.find(T[tr]);
        }
        int ans=0;
        for (int i=0;i<x-n+1;i++)
            for (int j=0;j<y-m+1;j++){
            //cout<<i<<" !! "<<j<<" "<<counts[i][j]<<endl;
            if (counts[i][j]==n)
                ans++;
            }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2014-04-18 17:28  KRisen  阅读(286)  评论(0编辑  收藏  举报