UVa 12886 - The Big Painting

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

兩個 2D 模式找出現的次數。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4 4 10 10
oxxo
xoox
xoox
oxxo
xxxxxxoxxo
oxxoooxoox
xooxxxxoox
xooxxxoxxo
oxxoxxxxxx
ooooxxxxxx
xxxoxxoxxo
oooxooxoox
oooxooxoox
xxxoxxoxxo

Sample Output

1
4

Solution

做法來源:http://www.csie.ntnu.edu.tw/~u91029/StringMatching.html#5

演算法筆記-2D String Matching: Baker-Bird Algorithm

步驟 1.
把 T 橫切成一條一條,
把 P 橫切成一條一條,
然後每一條 T 都執行 Multi-Pattern String Matching,例如Aho-Corasick Algorithm。
如果第 a 條 P ,從 T[i,j] 開始出現,那麼就進行紀錄:M[i,j] = a。
M 是一個跟 T 一樣大的陣列。

步驟 2.
把M直切成一條一條,
每一條M都執行String Matching,例如Morris-Pratt Algorithm。
看看是否出現1234567…n這個字串(剛剛P共有n條)。

要點
當 P 有某兩條相同時,則要小心處理,把這兩條的編號設為相同。
AC 自動機不用跑匹配的後綴,因為必然是沒有的,所以在這裡的 AC 自動機寫法比較特別。

速度看起來挺慢的,也許 hash 或者是 FFT 某方面對於這種會稍微快一點?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
// similar 11019 - Matrix Matcher
#define MAXN 2048
char T[MAXN][MAXN], P[MAXN][MAXN];
int M[MAXN][MAXN];
//<AC automation>
struct Node {
Node *next[26], *fail;
int matched, label;
Node() {
fail = NULL;
matched = -1;
label = -1;
memset(next, 0, sizeof(next));
}
};
int insertTrie(const char str[], Node *root, int label) {
static Node *p;
static int i, idx;
p = root;
for(i = 0; str[i]; i++) {
idx = str[i]-'a';
if(p->next[idx] == NULL)
p->next[idx] = new Node();
p = p->next[idx];
}
if(p->label == -1)
p->label = label;
return p->label;
}
void buildACautomation(Node *root) {
queue<Node*> Q;
Node *nd, *p;
root->fail = NULL;
Q.push(root);
while(!Q.empty()) {
nd = Q.front(), Q.pop();
for(int i = 0; i < 26; i++) {
if(nd->next[i] == NULL)
continue;
Q.push(nd->next[i]);
p = nd->fail;
while(p != NULL && p->next[i] == NULL)
p = p->fail;
if(p == NULL)
nd->next[i]->fail = root;
else
nd->next[i]->fail = p->next[i];
}
}
}
void quertACautomaiton(const char* str, Node *root, int row) {
static Node *p, *q;
static int i, idx;
p = root;
for(i = 0; str[i]; i++) {
idx = str[i]-'a';
while(p != root && p->next[idx] == NULL)
p = p->fail;
p = p->next[idx];
p = (p == NULL) ? root : p;
q = p;
M[row][i] = -1;
if(q != root && q->label >= 0)
M[row][i] = q->label;
}
}
void freeTrie(Node *root) {
queue<Node*> Q;
Node *nd;
while(!Q.empty()) {
nd = Q.front(), Q.pop();
for(int i = 0; i < 26; i++)
if(nd->next[i] != NULL)
Q.push(nd->next[i]);
delete nd;
}
}
//</AC automation>
int kmpTable[MAXN];
void KMPtable(int P[], int len) {
int i, j;
kmpTable[0] = -1, i = 1, j = -1;
while(i < len) {
while(j >= 0 && P[j+1] != P[i])
j = kmpTable[j];
if(P[j+1] == P[i])
j++;
kmpTable[i++] = j;
}
}
int KMPMatching(int T[], int P[], int tlen, int plen) {
int i, j;
int matchCnt = 0;
for(i = 0, j = -1; i < tlen; i++) {
while(j >= 0 && P[j+1] != T[i])
j = kmpTable[j];
if(P[j+1] == T[i]) j++;
if(j == plen-1) {
matchCnt++;
j = kmpTable[j];
}
}
return matchCnt;
}
int main() {
int testcase;
int n, m, x, y;
int i, j, k;
int pattern[MAXN], str[MAXN];
while(scanf("%d %d", &x, &y) == 2) {
scanf("%d %d", &n, &m);
Node *root = new Node();
for(i = 0; i < x; i++) {
scanf("%s", P[i]);
pattern[i] = insertTrie(P[i], root, i);
}
for(i = 0; i < n; i++)
scanf("%s", T[i]);
buildACautomation(root);
for(i = 0; i < n; i++)
quertACautomaiton(T[i], root, i);
/*for(i = 0; i < x; i++)
printf("%d xx\n", pattern[i]);
for(i = 0; i < n; i++, puts(""))
for(j = 0; j < m; j++)
printf("%3d ", M[i][j]);*/
KMPtable(pattern, x);
int ret = 0;
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++)
str[j] = M[j][i];
ret += KMPMatching(str, pattern, n, x);
}
printf("%d\n", ret);
freeTrie(root);
}
return 0;
}
/*
4 4 10 10
oxxo
xoox
xoox
oxxo
xxxxxxoxxo
oxxoooxoox
xooxxxxoox
xooxxxoxxo
oxxoxxxxxx
ooooxxxxxx
xxxoxxoxxo
oooxooxoox
oooxooxoox
xxxoxxoxxo
*/