这个题目要求在一个大矩阵里面匹配一个小矩阵,是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 ",ans); } return 0; }