Cod sursa(job #1799963)

Utilizator thewildnathNathan Wildenberg thewildnath Data 7 noiembrie 2016 06:55:49
Problema Aho-Corasick Scor 100
Compilator c Status done
Runda Arhiva educationala Marime 6.54 kb
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
//#include "vector.c"
//#include "queue.c"

// HELPER
void *ptr_int(int val) {
  int *temp = malloc(sizeof(int));
  *temp = val;
  return temp;
}

int val_int(void *ptr) {
  return *(int *)ptr;
}
//

// VECTOR
typedef struct vector {
  size_t capacity;
  size_t size;

  bool (*empty)(struct vector *);
  void (*push_back)(struct vector *, void *);
  void (*pop_back)(struct vector *);

  void **elem;
} vector;

bool v_empty(vector *v) {
  return v->size == 0;
}

void push_back(vector *v, void *object) {
  if (v->size == v->capacity) {
    if (v->capacity == 0)
      v->capacity = 1;
    else
      v->capacity *= 2;
    v->elem = realloc(v->elem, v->capacity * sizeof(void *));
  }

  v->elem[v->size] = object;
  ++v->size;
}

void pop_back(vector *v) {
  //assert(v->size > 0);
  --v->size;
  free(v->elem[v->size]);
}

// Constructor
// Return a pointer to an empty vector struct
vector *new_vector() {
  vector *v = malloc(sizeof(vector));

  v->capacity = 0;
  v->size = 0;

  v->empty = &v_empty;
  v->push_back = &push_back;
  v->pop_back = &pop_back;

  v->elem = NULL;

  return v;
}
//

// QUEUE
typedef struct container {
  void *object;
  struct container *next;
} container;

// Container Contructor
container *new_container(void *object) {
  container *c = malloc(sizeof(container));
  c->object = object;
  c->next = NULL;
  return c;
}

typedef struct queue {
  struct container *begin;
  struct container *end;

  bool (*empty)(struct queue *);
  void *(*front)(struct queue *);
  void (*push)(struct queue *, void *);
  void (*pop)(struct queue *);
} queue;

bool q_empty(queue *q) {
  return q->begin == NULL;
}

void *front(queue *q) {
  return q->begin->object;
}

void push(queue *q, void *object) {
  container *c = new_container(object);

  if (q->begin == NULL) {
    q->begin = c;
    q->end = c;
  } else {
    q->end->next = c;
    q->end = c;
  }
}

void pop(queue *q) {
  //assert(!q->empty());
  container *temp = q->begin;

  if (q->begin == q->end) {
      q->begin = NULL;
      q->end = NULL;
  } else
    q->begin = q->begin->next;

  free(temp->object);
  free(temp);
}

queue *new_queue() {
  queue *q = malloc(sizeof(queue));
  q->begin = NULL;
  q->end = NULL;

  q->empty = &q_empty;
  q->front = &front;
  q->push = &push;
  q->pop = &pop;

  return q;
}
//

enum {
  SIGMA = 26,
  NMAX = 100,
  WORD_LENGTH = 10000,
  STR_LENGTH = 1000000
};

typedef struct state {
  int id;
  int ch;
  int sum;
  int degree;
  bool solved;
  struct state *father;
  struct state *fail;
  struct state *trans[SIGMA];
} state;

typedef struct ahocorasick {
  vector *states;
  state *root;
} ahocorasick;

int n;
char str[STR_LENGTH + 1];

state *ends[1 + NMAX];

ahocorasick *aho;

// State Constructor
state *new_node(ahocorasick *aho, int ch, state *father) {
  state *node = malloc(sizeof(state));

  node->id = aho->states->size;
  node->ch = ch;
  node->sum = 0;
  node->degree = 0;
  node->father = father;
  node->fail = aho->root;
  for (int i = 0; i < SIGMA; ++i)
    node->trans[i] = NULL;
  aho->states->push_back(aho->states, node);

  return node;
}

// AhoCorasick Constructor
ahocorasick *new_ahocorasick () {
  ahocorasick *aho = malloc(sizeof(ahocorasick));

  aho->states = new_vector();
  aho->root = new_node(aho, -1, NULL);
  // For easier and memory efficient implementation of the build_fails function
  aho->root->father = aho->root;
  aho->root->fail = aho->root;

  return aho;
}

void add_word(ahocorasick *aho, char *word, int index) {
  int length = strlen(word);
  state *node = aho->root;

  for (int i = 0; i < length; ++i) {
    int ch = (int)(word[i] - 'a');
    if (node->trans[ch] == NULL)
      node->trans[ch] = new_node(aho, ch, node);
    node = node->trans[ch];
  }

  ends[index] = node;
}

void print_state(ahocorasick *aho, state *curr) {
  if (curr != aho->root)
      print_state(aho, curr->father);
  printf("%c", ('a' + curr->ch));
}

void build_fails(ahocorasick *aho) {
  queue *q = new_queue();
  q->push(q, ptr_int(0));

  while (!q->empty(q)) {
    int id = val_int(q->front(q));
    q->pop(q);
    state *curr = aho->states->elem[id];

    if (curr->father != aho->root) {
      state *temp = curr->father->fail;

      while (temp != aho->root && temp->trans[curr->ch] == NULL)
        temp = temp->fail;
      if (temp->trans[curr->ch] != NULL)
         temp = temp->trans[curr->ch];

      curr->fail = temp;
      ++curr->fail->degree;
      ++curr->father->degree;

    } // else curr->fail will always be aho->root(implicitely)

    //print_state(aho, curr);
    //printf("\n");
    //print_state(aho, curr->fail);
    //printf("\n");

    for (int ch = 0; ch < SIGMA; ++ch)
      if (curr->trans[ch] != NULL) {
        q->push(q, ptr_int(curr->trans[ch]->id));
      }
  }

  free(q);
}

void run_automaton(ahocorasick *aho, char *str) {
  int length = strlen(str);
  state *curr = aho->root;

  for (int i = 0; i < length; ++i) {
    int ch = (int)(str[i] - 'a');
    while (curr != aho->root && curr->trans[ch] == NULL)
      curr = curr->fail;
    if (curr->trans[ch] != NULL)
      curr = curr->trans[ch];
    ++curr->sum;
  }
}

void finalize(ahocorasick *aho) {
  queue *q = new_queue();

  for (int i = 0; i < aho->states->size; ++i)
    if (!((state *)aho->states->elem[i])->degree)
      q->push(q, ptr_int(i));

  while (!q->empty(q)) {
    int id = val_int(q->front(q));
    q->pop(q);
    state *curr = aho->states->elem[id];

    curr->fail->sum += curr->sum;
    --curr->fail->degree;
    if (curr->fail != aho->root && curr->fail->degree == 0)
      q->push(q, ptr_int(curr->fail->id));

    --curr->father->degree;
    if (curr->father != aho->root && curr->father->degree == 0)
      q->push(q, ptr_int(curr->father->id));
  }

  free(q);
}

void read_and_build() {
  freopen("ahocorasick.in", "r", stdin);

  aho = new_ahocorasick();

  scanf("%s", str);
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    char word[WORD_LENGTH + 1];
    scanf("%s", word);

    add_word(aho, word, i);
  }

  build_fails(aho);
}

void print() {
  freopen("ahocorasick.out", "w", stdout);
  for (int i = 1; i <= n; ++i)
    printf("%d\n", ends[i]->sum);
}

int main() {
  setbuf(stdout, NULL);
  read_and_build();
  run_automaton(aho, str);
  finalize(aho);
  print(aho);

  return 0;

}