Cod sursa(job #1513786)

Utilizator Andreiii500Andrei Puiu Andreiii500 Data 29 octombrie 2015 22:56:11
Problema Aho-Corasick Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 4.47 kb
#include<iostream>
#include<fstream>
#include<string.h>
using namespace std;

#define dim 1000005
#define dim2 10000*100 + 5 // Presupunand ca toate cuvintele sunt diferite

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

struct trie
{
    trie *tata, *faillink;
    trie *fiu[26];
    int cnt,nrfii;
    char lit; /// Litera adaugata ca sa ajung aici [0, 1, ... , 25]

    trie()
    {
        int i;

        cnt = 0;
        nrfii = 0;
        tata = this;
        for(i=0; i<26; ++i) fiu[i] = NULL;
    }
};

trie *vf = new trie;
trie *coada[dim2];
char text[dim];
int fcv[10005];
int cnt;

void add(char cuv[], int index_cuv)
{
    int i,n;
    trie *p, *next;

    p = vf;

    n = strlen(cuv);
    for(i=0; i<n; ++i)
    {
        next = p->fiu[cuv[i] - 'a'];
        if(next != NULL) p = next;
        else
        {
            p->fiu[cuv[i]-'a'] = new trie;
            p->fiu[cuv[i]-'a']->tata = p;
            p->fiu[cuv[i]-'a']->lit = cuv[i]-'a';
            p->nrfii += 1;
            p = p->fiu[cuv[i]-'a'];
        }
    }
    p->cnt = index_cuv;
}

int aparitii(char cuv[])
{
    int i,n;
    trie *p;

    p = vf;

    n = strlen(cuv);
    i=0;
    while(i<n && p!=NULL)
    {
        p = p->fiu[cuv[i] - 'a'];
        ++i;
    }

    if(p) return p->cnt;
    else return 0;
}

void find_faillink(trie *p) /// A se apela numai pentru noduri de nivel 2 sau mai mic!
{
    trie *i;

    i = p->tata->faillink;
    while(i->fiu[p->lit] == NULL  &&  i!=vf)
    {
        i = i->faillink;
    }

    if(i->fiu[p->lit] == NULL) /// Am ajuns pana la vf si n-am gasit sufix (nici macar pe vf)
        p->faillink = vf;
    else /// Am gasit primul sufix (cel maxim)
        p->faillink = i->fiu[p->lit];
}

void calc_solutii(trie *p)
{
    trie *q;

    q = p;
    while(q!=vf) /// Daca am gasit o solutie, toate sufixele sunt si ele solutii
    {
        ++fcv[q->cnt];
        q = q->faillink;
    }
}

int main()
{
    char cuv[10005];
    int n,i,j,m;
    trie *p, *q;

    in>>text;
    in>>n;

    for(i=1; i<=n; ++i)
    {
        in>>cuv;

        //cout<<cuv<<"\n";

       add(cuv,i);

       //out<<aparitii(cuv)<<"\n";
    }

    ///  Precalculez primele doua nivele
    /// si creez o coada

    cnt = 0;
    vf->faillink = vf;
    for(i=0; i<26; ++i)
        if(vf->fiu[i] != NULL)
        {
            vf->fiu[i]->faillink = vf;

            for(j=0; j<26; ++j)
                if(vf->fiu[i]->fiu[j] != NULL)
                {
                    ++cnt;
                    coada[cnt] = vf->fiu[i]->fiu[j];
                }
        }

    //cout<<"i=0    nod: "<<vf<<"    tata: "<<vf->tata<<"    faillink: "<<vf->faillink<<"\n\n";
    //cout<<"i=a    nod: "<<vf->fiu[0]<<"    tata: "<<vf->fiu[0]->tata<<"    faillink: "<<vf->fiu[0]->faillink<<"    cnt="<<vf->fiu[0]->cnt<<"\n";
    //cout<<"i=b    nod: "<<vf->fiu[1]<<"    tata: "<<vf->fiu[1]->tata<<"    faillink: "<<vf->fiu[1]->faillink<<"    cnt="<<vf->fiu[1]->cnt<<"\n";
    //cout<<"i=c    nod: "<<vf->fiu[2]<<"    tata: "<<vf->fiu[2]->tata<<"    faillink: "<<vf->fiu[2]->faillink<<"    cnt="<<vf->fiu[2]->cnt<<"\n\n";

    i=1;
    while(i <= cnt)
    {
        find_faillink(coada[i]);
        for(j=0; j<26; ++j)
            if(coada[i]->fiu[j] != NULL)
            {
                ++cnt;
                coada[cnt] = coada[i]->fiu[j];
            }
        //cout<<"i="<<i<<"    nod: "<<coada[i]<<"    tata: "<<coada[i]->tata<<"    faillink: "<<coada[i]->faillink<<"    cnt="<<coada[i]->cnt<<"\n";
        ++i;
    }
    //cout<<"\n";

    m = strlen(text);
    p = vf;
    for(i=0; i<m; ++i)
    {
        //cout<<"i="<<i<<"\n";
        if(p->fiu[text[i] - 'a'] != NULL)
        {
            // As putea crea o functie avansez(), dar pentru doar doua instructiuni... nu merita
            p = p->fiu[text[i] - 'a'];
            calc_solutii(p);
        }
        else
        {
            while(p->fiu[text[i] - 'a'] == NULL  &&  p!=vf) /// Caut primul sufix care ar putea continua cuvantul
            {
                p = p->faillink;
            }
            if(p->fiu[text[i] - 'a'] != NULL)
            {
                p = p->fiu[text[i] - 'a'];
                calc_solutii(p);
            }
            // else raman pe loc
        }

        //for(j=1; j<=n; ++j) cout<<fcv[j]<<" "; cout<<"\n";
    }

    for(i=1; i<=n; ++i) out<<fcv[i]<<"\n";

    return 0;
}