Cod sursa(job #2680179)

Utilizator nicolaefilatNicolae Filat nicolaefilat Data 2 decembrie 2020 21:02:44
Problema Aho-Corasick Scor 95
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.62 kb
#include <iostream>
#include <fstream>
#include <tuple>
#include <queue>
#include <vector>
#include <stack>

const int MAXLIT = 26;
const int MAXN = 101;

using namespace std;

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


struct Nod{
    Nod *muchii[MAXLIT];
    Nod *suffixLink;
    int aparitii = 0;
    Nod(){
        suffixLink = nullptr;
        for(int i = 0; i < MAXLIT; i++)
            muchii[i] = nullptr;
    }
};
class Trie{
public:

    stack<Nod*>noduriInvers;
    Trie(){
        radacina = new Nod();
        radacina->suffixLink = radacina;
    }
    void adauga(const string &sir){
        Nod *nod = radacina;
        for(char caracter : sir){
            int poz = caracter - 'a';
            if(nod->muchii[poz] != nullptr){
                nod = nod->muchii[poz];
            }else{
                Nod *nou = new Nod();
//                nou->s = nod->s + caracter;
                nod->muchii[poz] = nou;
                nod = nod->muchii[poz];
            }
        }
    }
    int numarAparitii(const string &sir){
        Nod *nod = radacina;
        for(char caracter : sir){
            int poz = caracter - 'a';
            nod = nod->muchii[poz];
        }
        return nod->aparitii;
    }
    void construiesteFailureLink(){
        /// tuple de Nod, Tata si Caracter Curent
        queue<tuple<Nod*,Nod*,char>>coada;
        for(int i = 0; i < MAXLIT; i++)
            if(radacina->muchii[i] != nullptr){
                coada.push(make_tuple(radacina->muchii[i],radacina,'a' + i));
            }
        while(coada.size()){
            auto it = coada.front();
            Nod *curent = get<0>(it);
            Nod *tata = get<1>(it);
            char x = get<2>(it);
            coada.pop();
            noduriInvers.push(curent);
            Nod *fail = tata->suffixLink;
            while(fail->muchii[x - 'a'] == nullptr){
                if(fail == radacina)
                    break;
                fail = fail->suffixLink;
            }
            if(fail->muchii[x - 'a'] != nullptr && fail->muchii[x - 'a'] != curent){
                curent->suffixLink = fail->muchii[x - 'a'];
            }else
                curent->suffixLink = radacina;
//            cout<<curent->s<<" -> ";
//            if(curent->suffixLink == radacina)
//                cout<<"radacina"<<endl;
//            else
//                cout<<curent->suffixLink->s<<endl;
            for(int i = 0; i < MAXLIT; i++){
                if(curent->muchii[i] != nullptr){
                    coada.push(make_tuple(curent->muchii[i],curent,i + 'a'));
                }
            }
        }
    }
    void rezolva(const string &input){
        Nod *nod = radacina;

        int index = 0;
        for(char caracter : input){
            int poz = caracter - 'a';
            index++;
            if(nod->muchii[poz] != nullptr){
                nod = nod->muchii[poz];
//                cout<<"sunt pe "<<nod->s<<endl;
                nod->aparitii++;
            }else{
                while(nod->muchii[poz] == nullptr){
                    if(nod == radacina)
                        break;
                    nod = nod->suffixLink;
                }

                if(nod->muchii[poz] != nullptr){
                    nod = nod->muchii[poz];
                    nod->aparitii++;
                }

            }
        }
    }
    void calculeazaAparitii(){
        while(noduriInvers.size()){
            Nod* nod = noduriInvers.top();
            noduriInvers.pop();
            for(int i = 0; i < MAXLIT; i++){
                Nod *vecin = nod->muchii[i];
                if(vecin != nullptr){
                    vecin->suffixLink->aparitii += vecin->aparitii;
                }
            }
        }
    }
    void afisare(){
        print(radacina);
    }

private:
    Nod *radacina;

    void print(Nod *nod){
//        cout<<nod->s<<" "<<nod->aparitii<<endl;
        for(int i = 0; i < MAXLIT; i++){
            if(nod->muchii[i] != nullptr){
                print(nod->muchii[i]);
            }
        }
    }


};

int main()
{

    in.tie(0);
    out.tie(0);
    ios::sync_with_stdio(false);

    string input;
    int n;
    in>>input>>n;
    Trie *trie = new Trie();
    vector<string>cuvinte(n);
    for(int i = 0; i < n; ++i){
        in>>cuvinte[i];
        trie->adauga(cuvinte[i]);
    }
    trie->construiesteFailureLink();
    trie->rezolva(input);
    trie->calculeazaAparitii();
    for(int i = 0; i < n; ++i)
        out<<trie->numarAparitii(cuvinte[i])<<'\n';

    return 0;
}