Cod sursa(job #3124395)

Utilizator MDiana15Diana M MDiana15 Data 28 aprilie 2023 14:44:07
Problema Aho-Corasick Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.47 kb
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <cstring>
#include <cassert>

#define ALPHMAX 26 // size of the alphabet


struct Node {
    int frequency; // how many times it appears
    Node *next[ALPHMAX];
    Node *link; // where we can go to;

    // initialise the new node
    Node() {
        frequency = 0;
        link = nullptr;
        memset(next, 0, sizeof(next));
    }
};

std::string input, guess;
int n;

// features of the TRIE we are creating for pattern matching
Node *root = new Node();
std::vector<Node *> leaves;



// TRIE creation
void insert(Node *&node, std::string &s, int position) {

    // we've reached end of the word given => create a new leaf
    if (position == s.size()) {
        leaves.push_back(node);
        return;
    }

    // get next character
    int forward = s[position] - 'a';

    // verify if the node already exists -> if not create a new node
    if (node->next[forward] == nullptr) {
        node->next[forward] = new Node();
    }

    insert(node->next[forward], s, position + 1);
}


int main() {

    freopen("ahocorasick.in","r",stdin);
    freopen("ahocorasick.out","w",stdout);

    std::cin >> input >> n;

    for (int i = 0; i < n; i++) {
        std::cin >> guess;

        // add the word guessed to the tree
        insert(root, guess, 0);

    }

    std::queue<Node *> queue;
    std::stack<Node *> st;

    queue.push(root);

    while (!queue.empty()) {
        auto current = queue.front();
        queue.pop();

        // keep track of seeing the current node -> used for anti-bfs
        st.push(current);

        for (int i = 0; i < ALPHMAX; i++) {
            // we can go forward using the i-th character in the alphabet

            if (current->next[i] != nullptr) {
                auto go = current->link;
                auto forward = current->next[i];

                // go up in the tree as much as possible
                while (go != nullptr && go != root && go->next[i] == nullptr) {
                    go = go->link;
                }

                // see why we reached the end
                if (go == root || go == nullptr) {
                    go = root;
                    if (forward != root->next[i] && root->next[i] != nullptr)
                        forward->link = root->next[i];
                    else
                        forward->link = root;
                } else {
                    forward->link = go->next[i];
                }

                assert(forward -> link != nullptr);
                queue.push(forward);
            }
        }
    }

    // start the process of matching from the root
    auto current = root;

    for (int i = 0; i < input.size(); i++) {
        // reached a dead end -> go back to the root
        if (current == nullptr)
            current = root;

        // traverse the TRIE as much as possible
        while (current != root && current != nullptr && current->next[input[i] - 'a'] == nullptr) {
            current = current->link;
        }

        if (current != nullptr && current->next[input[i] - 'a'] != nullptr) {
            current = current->next[input[i] - 'a'];
            current->frequency += 1;
        }
    }

    root->link = root;

    while (!st.empty()) {
        auto current = st.top();
        st.pop();

        current->link->frequency += current->frequency;
    }


    // for each given word/leaf output each frequency
    for (auto leaf: leaves) {
        std::cout << leaf->frequency << std::endl;
    }

    return 0;
}