Pagini recente » Borderou de evaluare (job #1736148) | Borderou de evaluare (job #2938369) | Borderou de evaluare (job #2912103) | Borderou de evaluare (job #1265982) | Cod sursa (job #3279687)
#include <fstream>
#include <string>
#include <queue>
#include <vector>
using namespace std;
const int NMAX = 100;
string sir;
string cuvinte[1 + NMAX];
const int SIGMA = 26;
struct Nod
{
Nod* parinte;
Nod* tranzitii[SIGMA];
bool tranzitiaEsteFiu[SIGMA];
Nod* nodSufixMaximal;
int numarVizite;
char caracter;
Nod()
{
this->parinte = nullptr;
for (int i = 0; i < SIGMA; ++i)
this->tranzitii[i] = nullptr;
for (int i = 0; i < SIGMA; ++i)
this->tranzitiaEsteFiu[i] = false;
this->nodSufixMaximal = nullptr;
this->numarVizite = 0;
this->caracter = '$';
}
~Nod()
{
this->parinte = nullptr;
for (int i = 0; i < SIGMA; ++i)
{
if (this->tranzitiaEsteFiu[i])
{
delete this->tranzitii[i];
this->tranzitii[i] = nullptr;
this->tranzitiaEsteFiu[i] = false;
}
}
this->nodSufixMaximal = nullptr;
this->numarVizite = 0;
this->caracter = '$';
}
};
Nod* radacinaTrie = new Nod();
queue<Nod*> coadaNoduri;
vector<Nod*> parcurgereBFS;
void initTrie()
{
radacinaTrie->parinte = radacinaTrie;
radacinaTrie->nodSufixMaximal = radacinaTrie;
}
void adaugaCuvInTrie(const string& cuvant)
{
Nod* nodCurent = radacinaTrie;
for (int i = 0; i < cuvant.size(); ++i)
{
if (!nodCurent->tranzitiaEsteFiu[cuvant[i] - 'a'])
{
nodCurent->tranzitii[cuvant[i] - 'a'] = new Nod();
nodCurent->tranzitiaEsteFiu[cuvant[i] - 'a'] = true;
nodCurent->tranzitii[cuvant[i] - 'a']->parinte = nodCurent;
nodCurent->tranzitii[cuvant[i] - 'a']->caracter = cuvant[i];
}
nodCurent = nodCurent->tranzitii[cuvant[i] - 'a'];
}
}
void bfsNoduriTrie()
{
coadaNoduri.emplace(radacinaTrie);
while (!coadaNoduri.empty())
{
Nod* nodCurent = coadaNoduri.front();
coadaNoduri.pop();
parcurgereBFS.push_back(nodCurent);
for (int i = 0; i < SIGMA; ++i)
if (nodCurent->tranzitiaEsteFiu[i])
coadaNoduri.push(nodCurent->tranzitii[i]);
}
}
void calculeazaAutomat()
{
for (int i = 0; i < SIGMA; ++i)
if (!radacinaTrie->tranzitiaEsteFiu[i])
radacinaTrie->tranzitii[i] = radacinaTrie;
for (int j = 1; j < parcurgereBFS.size(); ++j) // Fara radacina, de la 1 incepe.
{
Nod* nodCurent = parcurgereBFS[j];
nodCurent->nodSufixMaximal = nodCurent->parinte->nodSufixMaximal->tranzitii[nodCurent->caracter - 'a'];
if (nodCurent->nodSufixMaximal == nodCurent) // Cazul nodurilor ce corespund unui string de lungime exact 1.
nodCurent->nodSufixMaximal = radacinaTrie;
for (int i = 0; i < SIGMA; ++i)
{
if (nodCurent->tranzitii[i] != nullptr)
continue;
nodCurent->tranzitii[i] = nodCurent->nodSufixMaximal->tranzitii[i];
if (nodCurent->tranzitii[i] == nullptr)
nodCurent->tranzitii[i] = radacinaTrie;
}
}
}
void populeazaNumarVizite(const string& sir)
{
Nod* nodCurent = radacinaTrie;
++nodCurent->numarVizite;
for (int i = 0; i < sir.size(); ++i)
{
nodCurent = nodCurent->tranzitii[sir[i] - 'a'];
++nodCurent->numarVizite;
}
}
void propagaNumarVizite()
{
for (int i = (int)parcurgereBFS.size() - 1; i >= 0; --i)
{
Nod* nodCurent = parcurgereBFS[i];
if (nodCurent->nodSufixMaximal != nodCurent) // Cum e in cazul radacinii de exemplu.
nodCurent->nodSufixMaximal->numarVizite += nodCurent->numarVizite;
}
}
int solutie(const string& cuvant)
{
Nod* nodCurent = radacinaTrie;
for (int i = 0; i < cuvant.size(); ++i)
nodCurent = nodCurent->tranzitii[cuvant[i] - 'a'];
return nodCurent->numarVizite;
}
int main()
{
ios_base::sync_with_stdio(false);
ifstream in("ahocorasick.in");
ofstream out("ahocorasick.out");
in.tie(nullptr);
out.tie(nullptr);
initTrie();
in >> sir;
int n;
in >> n;
for (int i = 1; i <= n; ++i)
in >> cuvinte[i];
for (int i = 1; i <= n; ++i)
adaugaCuvInTrie(cuvinte[i]);
bfsNoduriTrie();
calculeazaAutomat();
populeazaNumarVizite(sir);
propagaNumarVizite();
for (int i = 1; i <= n; ++i)
out << solutie(cuvinte[i]) << '\n';
delete radacinaTrie;
in.close();
out.close();
return 0;
}