Cod sursa(job #2595008)

Utilizator SoranaAureliaCatrina Sorana SoranaAurelia Data 6 aprilie 2020 21:39:52
Problema Aho-Corasick Scor 95
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.64 kb
#include <fstream>
#include <vector>
#include <cctype>
#include <cstring>

#define AMAXLENGTH 1000005
#define DICTMAXLENGTH 10005
#define NMAX 105
#define DALF 26
using namespace std;

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

struct ac{
    vector<int> cuv; //indicii cuvintelor care se termina in nodul curent
    ac *copii[DALF];
    ac *fail;
    int nrpotriviri;

    ac(){
        nrpotriviri = 0;
        fail = NULL;
        memset(copii, 0, sizeof(copii));
    }
}*r, *q[DICTMAXLENGTH*DICTMAXLENGTH];

int ic, sc; // pt a parcurge q
int n;
int fin[NMAX];
char a[AMAXLENGTH];
char c[DICTMAXLENGTH];


void adaug(ac *nod, char *cuvant, int ind){   // adaugarea ca si in trie
    if(!isalpha(*cuvant)){
        nod->cuv.push_back(ind);
        return;
    }
    if(!nod->copii[*cuvant - 'a'])
        nod->copii[*cuvant - 'a'] = new ac();
    adaug(nod->copii[*cuvant - 'a'], cuvant+1,ind);
}

void citire(){
    f.getline(a, AMAXLENGTH);
    f>>n;
    f.get();
    for(int i=1; i<=n; i++){
        f.getline(c, DICTMAXLENGTH);
        adaug(r, c, i);
    }

}

void bfs(ac *t){
    ac *cautfail;
    t->fail = t;
    ic = sc = 1;
    for(q[ic] = t; ic<=sc; ic++){
        ac *fr = q[ic];
        for(int i=0; i<DALF; i++)
            if(fr->copii[i] != NULL){ // nodul caruia ii cautam failul

                for(cautfail = fr->fail; cautfail!=t && cautfail->copii[i]==NULL; cautfail = cautfail->fail);
                if(cautfail->copii[i]!=NULL && cautfail->copii[i] != fr->copii[i])
                    cautfail = cautfail->copii[i];
                fr->copii[i]->fail = cautfail;
                q[++sc] = fr->copii[i];

            }
    }
    t->fail = NULL;
}

void antibfs(ac *t){
    // parcurgem nodurile in ordinea invers a bfs-ului
    // daca avem caa, putem adauga si la fail (aka cel mai lung sufix) numarul aparitiilor

    for(int i=sc; i>0; i--){
        ac *fr = q[i];
        if(fr->fail!=NULL)
            fr->fail->nrpotriviri += fr->nrpotriviri;
        for(int j=0; j<fr->cuv.size(); j++)
            fin[fr->cuv[j]] = fr->nrpotriviri;

    }
}
void legaturi_sufix(){
    r->fail = r;
    bfs(r);

}

void solve(){
    ac *p = r;
    int lungime = strlen(a);
    for(int i=0; i<lungime; i++){
        int urm = a[i]-'a';
        for(;p->copii[urm]==NULL && p!=r; p=p->fail);
        if(p->copii[urm]!=NULL)
            p=p->copii[urm];
        p->nrpotriviri++;
    }
}
int main()
{
    r = new ac();
    citire();
    legaturi_sufix();
    solve();
    antibfs(r);
    for(int i=1; i<=n; i++)
        g<<fin[i]<<'\n';
    return 0;
}