|
| 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