Cod sursa(job #2843030)

Utilizator vlad2009Vlad Tutunaru vlad2009 Data 1 februarie 2022 21:15:12
Problema Aho-Corasick Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.19 kb
#include <fstream>
#include <algorithm>
#include <vector>
#include <queue>

const int MAX_N = 100;
const int SIGMA = 26;

struct Trie {
  int freq;
  Trie* children[SIGMA];
  Trie* failLink;

  Trie() {
    freq = 0;
    for (int i = 0; i < SIGMA; i++) {
      children[i] = NULL;
    }
    failLink = NULL;
  }
};

Trie* pos[1 + MAX_N];
std::vector<Trie*> order;

Trie* insert(Trie* root, char* S) {
  if (*S == '\0') {
    return root;
  } else {
    if (root->children[S[0] - 'a'] == NULL) {
      root->children[S[0] - 'a'] = new Trie();
    }
    return insert(root->children[S[0] - 'a'], S + 1);
  }
}

void ahoCorasick(Trie* root) {
  std::queue<Trie*> q;
  q.push(root);
  root->failLink = root;
  while (!q.empty()) {
    Trie* u = q.front();
    order.push_back(u);
    q.pop();
    for (int i = 0; i < SIGMA; i++) {
      if (u->children[i] != NULL) {
        u->children[i]->failLink = u->failLink;
        while (u->children[i]->failLink != root && u->children[i]->failLink->children[i] == NULL)  {
          u->children[i]->failLink = u->children[i]->failLink->failLink;
        }
        if (u->children[i]->failLink->children[i] != NULL && u != root) {
          u->children[i]->failLink = u->children[i]->failLink->children[i];
        }
        q.push(u->children[i]);
      }
    }
  }
}

void count(Trie* root, char* T) {
  Trie* u = root;
  for (int i = 0; T[i] != '\0'; i++) {
    while (u != root && u->children[T[i] - 'a'] == NULL) {
      u = u->failLink;
    }
    if (u->children[T[i] - 'a'] != NULL) {
      u = u->children[T[i] - 'a'];
    }
    u->freq++;
  }
}

void answer() {
  std::reverse(order.begin(), order.end());
  for (Trie* it : order) {
    it->failLink->freq += it->freq;
  }
}

int main() {
  std::ifstream fin("ahocorasick.in");
  std::ofstream fout("ahocorasick.out");
  Trie root;
  char* T = new char[1000000 + 1];
  char* C = new char[100000 + 1];
  int n;
  fin >> T >> n;
  for (int i = 1; i <= n; i++) {
    fin >> C;
    pos[i] = insert(&root, C);
  }
  ahoCorasick(&root);
  count(&root, T);
  answer();
  for (int i = 1; i <= n; i++) {
    fout << pos[i]->freq << "\n";
  }
  return 0;
}