題目鏈接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1960
題意:給出一個n×m
的矩陣一,在給出一個x×y
的矩陣二,求矩陣二在矩陣一中出現的次數。
思路:對於矩陣二的每行建立Trie,並在單詞結尾結點記錄走到該結點的爲行數c(有多個可開數組記錄),利用一個co[r][i]
數組記錄在矩陣一中以(r, i)
爲矩陣二的右上角,大小與矩陣二相同的矩陣包含的行數。對矩陣一每行均find()
一遍,最後掃描co
數組,統計值爲x的個數。
注:AC自動機並不是最優解法,時間效率仍是較低,最優解法爲二維hash。
代碼:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;
const int SIZE = 3e2 + 10;
const int N = 1e4 + 10;
const int NN = 1e3 + 10;
struct AC {
int ch[N][SIZE];
int sz;
int f[N];
bool ed[N];
int last[N];
int vt[N][SIZE];
int vn[N];
int co[NN][NN];
int newnode() {
memset(ch[sz], 0, sizeof(ch[sz]));
ed[sz] = false;
f[sz] = 0;
last[sz] = 0;
vn[sz] = 0;
return sz++;
}
void init() {
memset(co, 0, sizeof(co));
sz = 0;
newnode();
}
void insert(int id, char *s) {
int u = 0;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int idx = s[i];
if (!ch[u][idx])
ch[u][idx] = newnode();
u = ch[u][idx];
}
ed[u] = true;
vt[u][vn[u]++] = id;
}
void getfail() {
queue<int> q;
for (int i = 0; i < SIZE; i++)
if (ch[0][i])
q.push(ch[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < SIZE; i++) {
int v = ch[u][i];
if (v) {
q.push(v);
int r = f[u];
while (r && !ch[r][i])
r = f[r];
f[v] = ch[r][i];
last[v] = (ed[f[v]] ? f[v] : last[f[v]]);
}
else {
ch[u][i] = ch[f[u]][i];
}
}
}
}
void print(int r, int j, int c) {
if (j) {
for (int i = 0; i < vn[j]; i++)
if (r >= vt[j][i])
co[r - vt[j][i]][c]++;
print(r, last[j], c);
}
}
void find(int r, char *s) {
int u = 0;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int idx = s[i];
u = ch[u][idx];
if (ed[u]) print(r, u, i);
else if (last[u]) print(r, last[u], i);
}
}
}ac;
char Mat[NN][NN];
int main() {
int t_case;
scanf("%d", &t_case);
for (int i_case = 1; i_case <= t_case; i_case++) {
int n, m, x, y;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", Mat[i]);
ac.init();
scanf("%d%d", &x, &y);
for (int i = 1; i <= x; i++) {
char str[SIZE];
scanf("%s", str);
if (x <= n && y <= m)
ac.insert(i, str);
}
int ans = 0;
if (x <= n && y <= m) {
ac.getfail();
for (int i = 1; i <= n; i++)
ac.find(i, Mat[i]);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (ac.co[i][j] == x)
ans++;
}
printf("%d\n", ans);
}
return 0;
}