UVa 1113 - Multiple Morse Matches

contents

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

Problem

給摩斯電碼的編碼方式,以及一串沒有切割的主字串,和可能使用的單字集,請問有多少不同的解析方式。

Sample Input

1
2
3
4
5
6
7
8
9
10
1
.---.--.-.-.-.---...-.---.
6
AT
TACK
TICK
ATTACK
DAWN
DUSK

Sample Output

1
2

Solution

這題很明顯地是一道 O(nm) 的動態規劃,dp[i] 表示長度為 i 的解析方法數,藉由 match S[i, j] 轉移成 dp[j] += dp[i]

為了加速 match 的速度,先將字典集轉換成摩斯電碼,插入到 trie 中,當要做 match 時,相當於在 trie 走訪,可以高效地降低 O(m) 的嘗試。變成 O(nn)

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
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <map>
#define MAXCHAR 2
#define MAXS (4096)
#define MAXNODE (1048576<<2)
#pragma comment( linker, "/STACK:1024000000,1024000000")
using namespace std;
class Trie {
public:
struct Node {
Node *next[MAXCHAR];
int cnt;
void init() {
cnt = 0;
memset(next, 0, sizeof(next));
}
} nodes[MAXNODE];
Node *root;
int size, cases;
Node* getNode() {
Node *p = &nodes[size++];
p->init();
return p;
}
void init() {
size = cases = 0;
root = getNode();
}
inline int toIndex(char c) {
return c == '.';
}
// merge trie
void merge_dfs(Node *p, Node *q) {
for (int i = 0; i < MAXCHAR; i++) {
if (q->next[i]) {
Node *u = p->next[i], *v = q->next[i];
if (u == NULL)
p->next[i] = getNode(), u = p->next[i];
u->cnt += v->cnt;
merge_dfs(u, v);
}
}
}
void merge(const Trie &other) {
merge_dfs(root, other.root);
}
// basis operation
void insert(const char str[], int w) {
Node *p = root;
for (int i = 0, idx; str[i]; i++) {
idx = toIndex(str[i]);
if (p->next[idx] == NULL)
p->next[idx] = getNode();
p = p->next[idx];
}
p->cnt += w;
}
int find(const char str[]) {
Node *p = root;
for (int i = 0, idx; str[i]; i++) {
idx = toIndex(str[i]);
if (p->next[idx] == NULL)
p->next[idx] = getNode();
p = p->next[idx];
}
return p->cnt;
}
void free() {
return ;
// owner memory pool version
queue<Node*> Q;
Q.push(root);
Node *u;
while (!Q.empty()) {
u = Q.front(), Q.pop();
for (int i = 0; i < MAXCHAR; i++) {
if (u->next[i] != NULL) {
Q.push(u->next[i]);
}
}
delete u;
}
}
} tool;
char S[MAXS], T[MAXS], buf[MAXS];
string morse[] = {
".-", "-...", "-.-.", "-..",
".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.",
"--.-", ".-.", "...", "-",
"..-", "...-", ".--", "-..-",
"-.--", "--.."};
int main() {
int testcase, n;
scanf("%d", &testcase);
while (testcase--) {
tool.init();
scanf("%s", S);
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%s", T);
int m = 0;
for (int j = 0; T[j]; j++)
for (int k = 0; morse[T[j] - 'A'][k]; k++)
buf[m++] = morse[T[j] - 'A'][k];
buf[m] = '\0';
tool.insert(buf, 1);
}
int len = (int) strlen(S);
int dp[MAXS] = {};
dp[0] = 1;
for (int i = 0; i < len; i++) {
Trie::Node *p = tool.root;
for (int j = i; j < len; j++) {
int u = tool.toIndex(S[j]);
if (p->next[u] == NULL)
break;
p = p->next[u];
dp[j+1] += dp[i] * p->cnt;
}
}
printf("%d\n", dp[len]);
if (testcase)
puts("");
tool.free();
}
return 0;
}
/*
*/