Cod sursa(job #2671701)

Utilizator nicolaefilatNicolae Filat nicolaefilat Data 12 noiembrie 2020 16:35:03
Problema Aho-Corasick Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.81 kb
#include <iostream>
#include <fstream>
#include <tuple>
#include <queue>
#include <vector>

const int MAXLIT = 30;
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;
    string s;
    char val;
    Nod(){
        val = '@';
        s = "";
        suffixLink = nullptr;
        for(int i = 0; i < MAXLIT; i++)
            muchii[i] = nullptr;
    }
};
class Trie{
public:

    Trie(){
        radacina = new Nod();
        radacina->suffixLink = radacina;
    }
    void adauga(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->val = caracter;
                nou->s = nod->s + caracter;
                nod->muchii[poz] = nou;
                nod = nod->muchii[poz];
            }
        }
        retinut[++cateStringuri] = nod;
    }
    int numarAparitii(int index){
        return retinut[index]->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();

            Nod *fail = tata->suffixLink;
            bool ok = false;
            while(!areCaracterul(fail,x)){
                if(fail == radacina)
                    break;
                fail = fail->suffixLink;
            }
            if(areCaracterul(fail,x) && fail->val != x && fail->muchii[x - 'a'] != curent){
                fail = fail->muchii[x - 'a'];
            }
            curent->suffixLink = fail;
//            cout<<curent->s<<" -> ";
//            if(fail == radacina)
//                cout<<"radacina"<<endl;
//            else
//                cout<<fail->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(string input){
        Nod *nod = radacina;

        int index = 0;
        for(char caracter : input){
            int poz = caracter - 'a';
            index++;
            if(areCaracterul(nod,caracter)){
                if(nod->val != caracter){
                    nod = nod->muchii[poz];
                    nod->aparitii++;
                }else
                    nod->aparitii++;
            }
            else{
                while(!areCaracterul(nod,caracter)){
                    if(nod == radacina)
                        break;
                    nod = nod->suffixLink;
                }
                if(areCaracterul(nod,caracter)){
                    if(nod->val != caracter){
                        nod = nod->muchii[poz];
                        nod->aparitii++;
                    }else
                        nod->aparitii++;
                }
            }
        }
    }
    void aparitii(){
        calculeazaAparitii(radacina);
    }
    void afisare(){
        print(radacina);
    }

private:
    Nod *retinut[MAXN];
    int cateStringuri = 0;
    Nod *radacina;

    bool areCaracterul(Nod *nod,char c){
        if(nod->val == c)
            return true;
        int pozitie = c - 'a';
        if(nod->muchii[pozitie] != nullptr)
            return true;
        return false;
    }
    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]);
            }
        }
    }
    void calculeazaAparitii(Nod *nod){
        for(int i = 0; i < MAXLIT; i++){
            Nod* vecin = nod->muchii[i];
            if(vecin != nullptr){
                calculeazaAparitii(vecin);
                vecin->suffixLink->aparitii += vecin->aparitii;
            }
        }
    }

};

int main()
{
    string input;
    int n;
    in>>input>>n;
    Trie *trie = new Trie();
    for(int i = 1; i <= n; i++){
        string sir;
        in>>sir;
        trie->adauga(sir);
    }
    trie->construiesteFailureLink();
    trie->rezolva(input);
    trie->aparitii();
    for(int i = 1; i <= n; i++)
        out<<trie->numarAparitii(i)<<"\n";

    return 0;
}