Pagini recente » Cod sursa (job #1290211) | Cod sursa (job #1294413) | Cod sursa (job #1985180) | Cod sursa (job #1815781) | Cod sursa (job #3307359)
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
ifstream cin("ahocorasick.in");
ofstream cout("ahocorasick.out");
/*
Aho-Corasick
Acest algoritm este practic o generalizare
a algoritmului KMP (varianta cu automaton).
In termeni tehnici, exista aceste suffixLinks
(atunci cand desenam se vad ca niste arce in sus din trie)
care reprezinta pentru fiecare nod exact finalul
celui mai lung sufix prefix din algoritmul KMP,
dar considerand toate nodurile din trie, nu doar
cele de pe path ul de la root la nod.
Pentru a gasi aceste suffixLinks sunt 2 variante:
1. recursivitate indirecta
2. bfs
Acest cod foloseste varianta 2.
(am trimis in trecut un cod si cu prima varianta,
dar implementat mult mai urat :))
*/
class Node {
public:
Node** kids;
Node* suffixLink;
int cnt;
Node(int alphaSize) {
kids = new Node*[alphaSize];
for (int i = 0; i < alphaSize; i++) {
kids[i] = NULL;
}
suffixLink = NULL;
cnt = 0;
}
};
class AhoCorasick {
public:
Node* root;
int alphaSize;
AhoCorasick(int size) {
alphaSize = size;
root = new Node(size);
}
bool checkChild(Node* node, int childId) {
return (node->kids[childId] != NULL);
}
void addChild(Node* node, int childId) {
node->kids[childId] = new Node(alphaSize);
}
Node* insert(string s) {
Node* node = root;
for (char ch: s) {
int childId = int(ch - 'a');
if (!checkChild(node, childId)) {
addChild(node, childId);
}
node = node->kids[childId];
}
return node;
}
void solvePrefix(Node* node, int childId) {
Node* pref = node->suffixLink;
while (pref != root && !checkChild(pref, childId)) {
pref = pref->suffixLink;
}
if (checkChild(pref, childId) && pref->kids[childId] != node->kids[childId]) {
node->kids[childId]->suffixLink = pref->kids[childId];
} else {
node->kids[childId]->suffixLink = root;
}
}
void build() {
root->suffixLink = root;
queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node* node = q.front();
q.pop();
for (int i = 0; i < alphaSize; i++) {
if (checkChild(node, i)) {
solvePrefix(node, i);
q.push(node->kids[i]);
}
}
}
}
void solve(string s) {
Node* node = root;
for (char ch: s) {
int childId = int(ch - 'a');
while (node != root && !checkChild(node, childId)) {
node = node->suffixLink;
}
if (checkChild(node, childId)) {
node = node->kids[childId];
}
node->cnt++;
}
vector<Node*> bfsOrder;
bfsOrder.push_back(root);
for (int i = 0; i < int(bfsOrder.size()); i++) {
Node* node = bfsOrder[i];
for (int j = 0; j < alphaSize; j++) {
if (checkChild(node, j)) {
bfsOrder.push_back(node->kids[j]);
}
}
}
for (int i = bfsOrder.size() - 1; i >= 0; i--) {
bfsOrder[i]->suffixLink->cnt += bfsOrder[i]->cnt;
}
}
};
int main() {
int n;
string text;
cin >> text >> n;
AhoCorasick automaton(26);
Node* termNodes[n];
for (int i = 0; i < n; i++) {
string pattern;
cin >> pattern;
termNodes[i] = automaton.insert(pattern);
}
automaton.build();
automaton.solve(text);
for (int i = 0; i < n; i++) {
cout << termNodes[i]->cnt << '\n';
}
}