Cod sursa(job #2006007)

Utilizator Y0da1NUME JMECHER Y0da1 Data 28 iulie 2017 16:15:41
Problema Aho-Corasick Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 3.58 kb
#include <iostream>
#include <fstream>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
int n, pos=1;
char A [1000005];
char B [10005];
int ans [105];

class nod {
public:
    nod * fail, * sons[26], *parent;
    int eterminal, cnt;
    char c;
    nod()
    {
        memset(sons, 0, sizeof(sons));
        fail = NULL;
        eterminal =0;
        cnt =0;
    }
};
nod T;
vector <nod *> Q;
queue <nod *> Q2;
void ins(char * c, nod * curr)
{
    //cout<<"INSEREZ FIUL "<<c[0]<<" LA NODUL "<<curr<<" ("<<curr->c<<")\n";
    int fiu = (int)(c[0]-'a');
    if(c[0]==0) //caracter nul
    {
        curr->eterminal=pos;
        ++pos;
    }
    if('a'<=c[0] && c[0]<='z')
    {
        if(curr->sons[fiu]==NULL)         //daca nu am mai avut fiul asta
            curr->sons[fiu]=new nod;
        curr->sons[fiu]->c=c[0];
        ins(c+1, curr->sons[fiu]);
    }

}
void befeu (nod * d)
{
    //Q.resize(256);
    nod * fail;
    //Q.push(d);
    for(int i=0;i<26;++i)
                if(d->sons[i]!=NULL)    //avem muchie cu litera respectiva
                {
                    d->sons[i]->parent=d->fail;
                    Q.push_back(d->sons[i]);
                }
    //while(!Q.empty())
    for(int j=0;j<Q.size();++j)
    {
        //d=Q.front();
        d=Q[j];
        //Q.pop();
        //++j;
        if (d==&T)
            continue;
        fail = d->parent;   //luam failu parintelui (cam ca la kmp)
        while(fail->sons[d->c-'a']==NULL && fail != &T)      //calculam fail function cam ca la KMP
        {
            fail=fail->fail;
        }
        d->fail = fail->sons[d->c-'a'];
        if(d->fail == NULL)
            d->fail = &T;
        if(d->fail == d)
            d->fail = &T;
        //cout<<"NODUL "<<d<<"("<<d->c<<") "<<" ARE FAIL "<<d->fail<<" ("<<d->fail->c<<")\n";
        for(int i=0;i<26;++i)
        {
            if(d->sons[i]!=NULL)    //avem muchie cu litera respectiva
                {
                d->sons[i]->parent=d->fail;
                Q.push_back(d->sons[i]);
                }
        }
    }
}
void befeu_special_doar_pt_infoarena()
{
    for(int i=Q.size()-1;i>=0;--i)
    {
        if(Q[i]->fail!=&T)
            Q[i]->fail->cnt+=Q[i]->cnt;
    }
    nod * d;
    Q2.push(&T);
    while(!Q2.empty())
    {
        d=Q2.front();
        if(d->eterminal>0)
            ans[d->eterminal]=d->cnt;
        Q2.pop();
        for(int i=0;i<26;++i)
        {
            if(d->sons[i]!=NULL)
                Q2.push(d->sons[i]);
        }
    }
}
int main()
{
    ifstream in ("ahocorasick.in");
    ofstream out ("ahocorasick.out");
    in>>A;
    in>>n;
    T.fail = &T;
    T.parent = &T;
    for(int i=0;i<n;++i)
    {
        in>>B;
        ins(B, &T);
    }
    befeu(&T);
    nod *curr = &T;
    int lg = strlen(A);
    for(int i=0;i<lg;++i)
    {
        while(curr->sons[A[i]-'a']==NULL && curr!=&T)
        {
            curr=curr->fail;
            //if(curr->eterminal>0)   //trebe sa pun si daca NU mergem in fail sa se actualizeze
                //curr->cnt++;
        }
        if(curr->sons[A[i]-'a']!=NULL)
        {
            //if(curr->fail->eterminal>0)
                //curr->fail->cnt++;
            curr=curr->sons[A[i]-'a'];
        }
        //if(curr->eterminal>0) //e o idee buna sa incrementezi la toate nodurile ca oricum le parcurgi si ADD consuma mai putin decat JG
        curr->cnt++;
    }
    befeu_special_doar_pt_infoarena();
    for(int i=1;i<=n;++i)
        out<<ans[i]<<"\n";
    return 0;
}