Skip to content

Commit f64ab38

Browse files
author
Takanori MAEHARA
committed
Blumer et al's online construction of factor automaton (aka. DAWG)
1 parent 97cd68b commit f64ab38

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

string/factor_automaton.cc

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//
2+
// Factor Automaton (aka. Directed Acyclig Word Graph)
3+
//
4+
// Description:
5+
// For a given string s, the factor automaton is an
6+
// automaton that accepts all substrings s[i,j).
7+
// The automaton has O(n) state.
8+
//
9+
// Algorithm:
10+
// Blumer et al's online construction.
11+
// See Section 6.3 of Crochemore-Rytter.
12+
//
13+
// Complexity:
14+
// O(n) time and space.
15+
//
16+
// Verified:
17+
// SPOJ 22531
18+
//
19+
// References:
20+
// A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht,
21+
// M. T. Chen, and J. Seiferas (1985):
22+
// The smallest automation recognizing the subwords of a text.
23+
// Theoretical Computer Science, vol. 40, pp. 31-55.
24+
//
25+
// M. Crochemore, and W. Rytter (1994):
26+
// Text Algorithms.
27+
// Oxford University Press.
28+
//
29+
#include <iostream>
30+
#include <vector>
31+
#include <cstdio>
32+
#include <queue>
33+
#include <algorithm>
34+
#include <functional>
35+
36+
using namespace std;
37+
38+
#define fst first
39+
#define snd second
40+
#define all(c) ((c).begin()), ((c).end())
41+
42+
struct factor_automaton {
43+
vector<vector<int>> link;
44+
vector<vector<bool>> bold;
45+
vector<int> suf;
46+
int root;
47+
int add_node() {
48+
link.push_back(vector<int>(0x100));
49+
bold.push_back(vector<bool>(0x100));
50+
suf.push_back(0);
51+
return link.size()-1;
52+
}
53+
factor_automaton(const char s[]) {
54+
add_node(); // = nil
55+
int sink = root = add_node();
56+
suf[root] = 0;
57+
for (int i = 0; s[i]; ++i) {
58+
char a = s[i];
59+
int newsink = add_node();
60+
link[sink][a] = newsink;
61+
bold[sink][a] = true;
62+
int w = suf[sink];
63+
while (w != 0 && link[w][a] == 0) {
64+
link[w][a] = newsink;
65+
bold[w][a] = false;
66+
w = suf[w];
67+
}
68+
int v = link[w][a];
69+
if (w == 0) suf[newsink] = root;
70+
else if (bold[w][a]) suf[newsink] = v;
71+
else {
72+
int newnode = add_node();
73+
link[newnode] = link[v];
74+
link[w][a] = newnode;
75+
bold[w][a] = true;
76+
suf[newsink] = newnode;
77+
suf[newnode] = suf[v];
78+
suf[v] = newnode;
79+
w = suf[w];
80+
while (w != 0 && link[w][a] == v && bold[w][a] == false) {
81+
link[w][a] = newnode;
82+
w = suf[w];
83+
}
84+
}
85+
sink = newsink;
86+
}
87+
}
88+
89+
void disp() {
90+
cout << "--- display ---" << endl;
91+
for (int i = 1; i < link.size(); ++i) {
92+
cout << " state " << i << endl;
93+
for (int c = 0; c < 0x100; ++c) {
94+
if (link[i][c] > 0) {
95+
if (bold[i][c]) cout << " ==" << (char)c << "==> " << link[i][c] << endl;
96+
else cout << " --" << (char)c << "--> " << link[i][c] << endl;
97+
}
98+
}
99+
}
100+
101+
}
102+
};
103+
104+
105+
int main() {
106+
for (char text[100000]; ~scanf("%s", text); ) {
107+
factor_automaton FA(text);
108+
109+
vector<pair<int,char>> prev(FA.link.size());
110+
queue<int> que;
111+
que.push(FA.root);
112+
while (prev[0].fst == 0) {
113+
int s = que.front();
114+
que.pop();
115+
for (int c = 'A'; c <= 'Z'; ++c) {
116+
//for (int c = 'A'; c <= 'B'; ++c) { // for test
117+
if (prev[FA.link[s][c]].fst == 0) {
118+
prev[FA.link[s][c]] = {s, c};
119+
que.push(FA.link[s][c]);
120+
//cout << s << " --" << (char)c << "--> " << FA.link[s][c] << endl;
121+
}
122+
}
123+
}
124+
int s = 0;
125+
vector<char> result;
126+
do {
127+
result.push_back(prev[s].snd);
128+
s = prev[s].fst;
129+
} while (s > 1);
130+
for (int i = result.size()-1; i >= 0; --i)
131+
printf("%c", result[i]);
132+
printf("\n");
133+
}
134+
}

0 commit comments

Comments
 (0)