Given an N * M matrix, your task is to find the number of occurences of an X * Y pattern.
Input
The first line contains a single integer t(t ≤ 15), the number of test cases.
For each case, the first line contains two integers N and M (N, M ≤ 1000). The next N lines contain M characters each.
The next line contains two integers X and Y (X, Y ≤ 100). The next X lines contain Y characters each.
Output
For each case, output a single integer in its own line, the number of occurrences.
Sample Input Output for Sample Input
2 1 1 x 1 1 y 3 3 abc bcd cde 2 2 bc cd | 0 2
|
题意:给出一个n*m的字符矩阵T,你的任务是找出给定的x*y的字符矩阵P出现了多少次。即需要在二维文本串T中查找二维模式串P。
思路:将矩阵P的每行插入Trie里,注意末尾标记这是第几行。然后对T的每一行在Trie里跑。
跑到标记处,比如T的第I行的J处有标记K,则count[i-k+1][j-y+2]++;
最后只需要遍历下count数组,==X的个数就是答案。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 15000
int Cnt = 0;
char T[1008][1008],str[108];
int count[1008][1008];
int n,m,x,y;
struct node
{
node * fail;
node * next[26];
bool flag[108];
node()
{
fail = NULL;
for(int i = 0;i < 26;i++)
next[i] = NULL;
memset(flag,0,sizeof(flag));
}
}*q[maxn];
int first,rear;
int idx(char c)
{
return c - 'a';
}
void Creat_Trie(char * s,node * root,int r)
{
int i,id,len;
node * p = root;
len = strlen(s);
for(int i = 0;i < len;i++)
{
id = idx(s[i]);
if(p -> next[id] == NULL)
p -> next[id] = new node();
p = p -> next[id];
}
p -> flag[r] = 1;
}
void Build_ac_automation(node * root)
{
q[rear++] = root;
node * p = NULL;
while(first < rear)
{
p = q[first++];
for(int i = 0;i < 26;i++)
{
if(p -> next[i] != NULL)
{
if(p == root)
{
p -> next[i] -> fail = root;
}
else
{
p -> next[i] -> fail = p -> fail -> next[i];
for(int j = 1;j <= 100;j++)
if(p -> fail -> next[i] -> flag[j])
p -> next[i] -> flag[j] = 1;
}
q[rear++] = p -> next[i];
}
else
{
if(p == root)
{
p -> next[i] = root;
}
else
{
p -> next[i] = p -> fail -> next[i];
}
}
}
}
}
void solve(char * s,int r,node * root)
{
int len = strlen(s);
node * p = root;
for(int i = 0;i < len;i++)
{
int id = idx(s[i]);
p = p -> next[id];
node * temp = p;
while(temp != NULL)
{
bool ok = false;
for(int j = 1;j <= 100;j++)
{
if(temp -> flag[j])
{
if(r-j+1 >= 0 && i-y+2 >= 0)
count[r-j+1][i-y+2]++;
ok = true;
}
}
if(!ok) break;
temp = temp -> fail;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int t; scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(count,0,sizeof(count));
for(int i = 1;i <= n;i++)
scanf("%s",T[i]);
scanf("%d%d",&x,&y);
node * root = new node();
first = rear = 0;
for(int i = 1;i <= x;i++)
{
scanf("%s",str);
Creat_Trie(str,root,i);
}
Build_ac_automation(root);
//接下来就是将字符串T在trie上跑。跑到有结点标记的地方。
for(int i = 1;i <= n;i++)
{
solve(T[i],i,root);
}
int ans = 0;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
if(count[i][j] == x)
ans++;
printf("%d\n",ans);
}
return 0;
}