Cod sursa(job #3279687)

Utilizator Razvan48Capatina Razvan Nicolae Razvan48 Data 23 februarie 2025 23:39:36
Problema Aho-Corasick Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.67 kb
#include <fstream>
#include <string>
#include <queue>
#include <vector>

using namespace std;

const int NMAX = 100;
string sir;
string cuvinte[1 + NMAX];

const int SIGMA = 26;

struct Nod
{
    Nod* parinte;

    Nod* tranzitii[SIGMA];
    bool tranzitiaEsteFiu[SIGMA];

    Nod* nodSufixMaximal;

    int numarVizite;

    char caracter;

    Nod()
    {
        this->parinte = nullptr;

        for (int i = 0; i < SIGMA; ++i)
            this->tranzitii[i] = nullptr;
        for (int i = 0; i < SIGMA; ++i)
            this->tranzitiaEsteFiu[i] = false;

        this->nodSufixMaximal = nullptr;

        this->numarVizite = 0;

        this->caracter = '$';
    }

    ~Nod()
    {
        this->parinte = nullptr;

        for (int i = 0; i < SIGMA; ++i)
        {
            if (this->tranzitiaEsteFiu[i])
            {
                delete this->tranzitii[i];
                this->tranzitii[i] = nullptr;
                this->tranzitiaEsteFiu[i] = false;
            }
        }

        this->nodSufixMaximal = nullptr;

        this->numarVizite = 0;

        this->caracter = '$';
    }
};

Nod* radacinaTrie = new Nod();

queue<Nod*> coadaNoduri;
vector<Nod*> parcurgereBFS;

void initTrie()
{
    radacinaTrie->parinte = radacinaTrie;

    radacinaTrie->nodSufixMaximal = radacinaTrie;
}

void adaugaCuvInTrie(const string& cuvant)
{
    Nod* nodCurent = radacinaTrie;

    for (int i = 0; i < cuvant.size(); ++i)
    {
        if (!nodCurent->tranzitiaEsteFiu[cuvant[i] - 'a'])
        {
            nodCurent->tranzitii[cuvant[i] - 'a'] = new Nod();
            nodCurent->tranzitiaEsteFiu[cuvant[i] - 'a'] = true;
            nodCurent->tranzitii[cuvant[i] - 'a']->parinte = nodCurent;
            nodCurent->tranzitii[cuvant[i] - 'a']->caracter = cuvant[i];
        }
        nodCurent = nodCurent->tranzitii[cuvant[i] - 'a'];
    }
}

void bfsNoduriTrie()
{
    coadaNoduri.emplace(radacinaTrie);

    while (!coadaNoduri.empty())
    {
        Nod* nodCurent = coadaNoduri.front();
        coadaNoduri.pop();
        parcurgereBFS.push_back(nodCurent);

        for (int i = 0; i < SIGMA; ++i)
            if (nodCurent->tranzitiaEsteFiu[i])
                coadaNoduri.push(nodCurent->tranzitii[i]);
    }
}

void calculeazaAutomat()
{
    for (int i = 0; i < SIGMA; ++i)
        if (!radacinaTrie->tranzitiaEsteFiu[i])
            radacinaTrie->tranzitii[i] = radacinaTrie;

    for (int j = 1; j < parcurgereBFS.size(); ++j) // Fara radacina, de la 1 incepe.
    {
        Nod* nodCurent = parcurgereBFS[j];

        nodCurent->nodSufixMaximal = nodCurent->parinte->nodSufixMaximal->tranzitii[nodCurent->caracter - 'a'];
        if (nodCurent->nodSufixMaximal == nodCurent) // Cazul nodurilor ce corespund unui string de lungime exact 1.
            nodCurent->nodSufixMaximal = radacinaTrie;

        for (int i = 0; i < SIGMA; ++i)
        {
            if (nodCurent->tranzitii[i] != nullptr)
                continue;

            nodCurent->tranzitii[i] = nodCurent->nodSufixMaximal->tranzitii[i];

            if (nodCurent->tranzitii[i] == nullptr)
                nodCurent->tranzitii[i] = radacinaTrie;
        }
    }
}

void populeazaNumarVizite(const string& sir)
{
    Nod* nodCurent = radacinaTrie;
    ++nodCurent->numarVizite;

    for (int i = 0; i < sir.size(); ++i)
    {
        nodCurent = nodCurent->tranzitii[sir[i] - 'a'];
        ++nodCurent->numarVizite;
    }
}

void propagaNumarVizite()
{
    for (int i = (int)parcurgereBFS.size() - 1; i >= 0; --i)
    {
        Nod* nodCurent = parcurgereBFS[i];

        if (nodCurent->nodSufixMaximal != nodCurent) // Cum e in cazul radacinii de exemplu.
            nodCurent->nodSufixMaximal->numarVizite += nodCurent->numarVizite;
    }
}

int solutie(const string& cuvant)
{
    Nod* nodCurent = radacinaTrie;

    for (int i = 0; i < cuvant.size(); ++i)
        nodCurent = nodCurent->tranzitii[cuvant[i] - 'a'];

    return nodCurent->numarVizite;
}

int main()
{
    ios_base::sync_with_stdio(false);

    ifstream in("ahocorasick.in");
    ofstream out("ahocorasick.out");

    in.tie(nullptr);
    out.tie(nullptr);

    initTrie();

    in >> sir;
    int n;
    in >> n;
    for (int i = 1; i <= n; ++i)
        in >> cuvinte[i];

    for (int i = 1; i <= n; ++i)
        adaugaCuvInTrie(cuvinte[i]);
    bfsNoduriTrie();

    calculeazaAutomat();

    populeazaNumarVizite(sir);
    propagaNumarVizite();

    for (int i = 1; i <= n; ++i)
        out << solutie(cuvinte[i]) << '\n';

    delete radacinaTrie;

    in.close();
    out.close();

    return 0;
}