Cod sursa(job #2760543)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 27 iunie 2021 17:21:24
Problema Aho-Corasick Scor 95
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.32 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <memory.h>

using namespace std;

class Trie {
public:
  Trie() {
    memset(sons, 0, sizeof(sons));
    failLink = 0;
    frequency = 0;
  }
  void add(string s, int position, vector<Trie*> &indexToNode) {
    _add(s, position, 0, indexToNode);
  }
  Trie *getSon(int index) {
    return sons[index];
  }
  Trie *getFailLink() {
    return failLink;
  }
  const vector<int>& getActiveSons() {
    return activeSons;
  }
  void setFailLink(Trie *fail) {
    failLink = fail;
  }
  void addFrequency(int k) {
    frequency += k;
  }
  int getFrequency() {
    return frequency;
  }
private:
  void _add(string &s, int position, int index, vector<Trie*> &indexToNode) {
    if (index == s.size()) {
      indexToNode[position] = this;
      return;
    }
    int childPos = s[index] - 'a';
    if (sons[childPos] == 0) {
      sons[childPos] = new Trie();
      activeSons.emplace_back(childPos);
    }
      
    sons[childPos]->_add(s, position, index + 1, indexToNode);
  }
    
  Trie *sons[26]; // representing the prefix tree
  Trie *failLink; // pointer to the longest prefix in the trie which is also suffix.
  int frequency;
  vector<int> activeSons;
};

class AhoCorasick {
public:
  AhoCorasick(int size): indexToNode(size, 0), dictionarySize(size) {
    root = new Trie();
    root->setFailLink(root);
  }
  void add(string s, int position) {
    root->add(s, position, indexToNode);
  }
  void buildFailLinks() {
    for (auto index: root->getActiveSons()) {
      Trie *son = root->getSon(index);
      son->setFailLink(root);
      Q.emplace_back(son);
    }
    
    Trie *curr;
    int pz = 0;
    while (pz < Q.size()) {
      curr = Q[pz++];
      for (auto index: curr->getActiveSons()) {
	Trie *son = curr->getSon(index);
	Trie *fail = curr->getFailLink();
	Trie *extension = fail->getSon(index);
	while (true) {
	  if (extension) {
	    // we managed to extend the previous longest prefix
	    son->setFailLink(extension);
	    break;
	  }
	  if (fail == root) {
	    // we didn't manage to extend any of the previous longest prefixes.
	    son->setFailLink(root);
	    break;
	  }
	  fail = fail->getFailLink();
	  extension = fail->getSon(index);
	}
	Q.emplace_back(son);
      }
    }
  }
  void digest(string s)
  {
    int pos = 0;
    Trie *crt = root;
    while (pos < s.size()) {
      int index = s[pos] - 'a';
      if (crt->getSon(index)) {
	crt = crt->getSon(index);
	crt->addFrequency(1);
	++pos;
	continue;
      }
      if (crt == root) {
	++pos;
	continue;
      }
      crt = crt->getFailLink();
    }

    for (;Q.size(); Q.pop_back())
      Q.back()->getFailLink()->addFrequency(Q.back()->getFrequency());      
  }
  int getFrequencyByIndex(int wordIndex) {
    return indexToNode[wordIndex]->getFrequency();
  }
private:
  int dictionarySize;
  Trie *root;
  vector<Trie*> indexToNode;
  vector<Trie*> Q;
};



int main()
{
  ifstream fin("ahocorasick.in");
  ofstream fout("ahocorasick.out");

  fin.sync_with_stdio(false);
  fin.tie(0);
  
  string s, word;
  int N;

  fin >> s >> N;
  AhoCorasick *automaton = new AhoCorasick(N);

  for (int i = 0; i < N; ++i) {
    fin >> word;
    automaton->add(word, i);
  }

  automaton->buildFailLinks();
  automaton->digest(s);

  for (int i = 0; i < N; ++i)
    fout << automaton->getFrequencyByIndex(i) << "\n";
  
  return 0;
}