Cod sursa(job #3242423)

Utilizator Mihai145Oprea Mihai Adrian Mihai145 Data 11 septembrie 2024 23:54:56
Problema Aho-Corasick Scor 15
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.95 kb
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <functional>

const int SIGMA = 26;

struct Node
{
    int cnt, mismatch;
    std::vector<int> out;

    Node()
    {
        cnt = 0, mismatch = -1;
        out = std::vector<int>(SIGMA, -1);
    }
};

class Aho
{
private:
    std::vector<Node> nodes;
    std::vector<int> word_ptr;

public:
    Aho()
    {
        nodes.push_back({}); // root node
    }

    void insert(const std::string &word)
    {
        int idx = 0;
        for (char c : word)
        {
            if (nodes[idx].out[c - 'a'] != -1)
                idx = nodes[idx].out[c - 'a'];
            else
            {
                nodes.push_back({});
                int new_idx = (int)nodes.size() - 1;

                nodes[idx].out[c - 'a'] = new_idx;
                idx = new_idx;
            }
        }

        word_ptr.push_back(idx);
    }

    bool can_extend(int node, int chr)
    {
        if (nodes[node].out[chr] == -1)
            return false;
        return true;
    }

    bool mismatch_can_extend(int node, int chr)
    {
        if (nodes[nodes[node].mismatch].out[chr] == -1)
            return false;
        return true;
    }

    void build()
    {
        std::function<void(int, int, int)> build_rec = [&](int node, int chr, int parent)
        {
            int candidate = nodes[parent].mismatch;
            while (candidate > 0 && !can_extend(candidate, chr))
                candidate = nodes[candidate].mismatch;

            if (candidate != parent && can_extend(candidate, chr))
                candidate = nodes[candidate].out[chr];

            nodes[node].mismatch = candidate;
            for (int i = 0; i < SIGMA; i++)
            {
                if (nodes[node].out[i] == -1)
                    continue;
                build_rec(nodes[node].out[i], i, node);
            }
        };

        nodes[0].mismatch = 0;

        for (int i = 0; i < SIGMA; i++)
        {
            if (nodes[0].out[i] == -1)
                continue;
            build_rec(nodes[0].out[i], i, 0);
        }
    }

    void walk(const std::string &text)
    {
        int idx = 0;
        for (char c : text)
        {
            if (nodes[idx].out[c - 'a'] != -1)
            {
                idx = nodes[idx].out[c - 'a'];
            }
            else
            {
                while (idx > 0 && !mismatch_can_extend(idx, c - 'a'))
                    idx = nodes[idx].mismatch;

                int next = idx;
                if (mismatch_can_extend(idx, c - 'a'))
                    next = nodes[nodes[idx].mismatch].out[c - 'a'];

                idx = next;
            }

            nodes[idx].cnt++;
        }
    }

    void propagate()
    {
        std::vector<int> bfs_order;
        std::queue<int> q;

        q.push(0);
        while (!q.empty())
        {
            int node = q.front();
            q.pop();
            bfs_order.push_back(node);

            for (int i = 0; i < SIGMA; i++)
            {
                if (nodes[node].out[i] == -1)
                    continue;
                q.push(nodes[node].out[i]);
            }
        }

        for (int i = (int)bfs_order.size() - 1; i >= 0; i--)
            nodes[nodes[bfs_order[i]].mismatch].cnt += nodes[bfs_order[i]].cnt;
    }

    std::vector<int> get_appearances()
    {
        std::vector<int> appearances(word_ptr.size(), 0);

        for (int i = 0; i < (int)word_ptr.size(); i++)
            appearances[i] = nodes[word_ptr[i]].cnt;

        return appearances;
    }
};

int main()
{
    std::ifstream cin("ahocorasick.in");
    std::ofstream cout("ahocorasick.out");

    std::string text;
    cin >> text;
    int n;
    cin >> n;

    Aho aho;
    for (int i = 0; i < n; i++)
    {
        std::string word;
        cin >> word;
        aho.insert(word);
    }

    aho.build();

    aho.walk(text);

    aho.propagate();

    auto appearances = aho.get_appearances();
    for (int ap : appearances)
        cout << ap << '\n';

    return 0;
}