Cod sursa(job #2443671)

Utilizator stoianmihailStoian Mihail stoianmihail Data 29 iulie 2019 00:23:22
Problema Aho-Corasick Scor 55
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.5 kb
#include <iostream>
#include <fstream>
#include <cstring>
#include <cassert>
#include <cctype>
#include <vector>

#define MAX_N 1000000
#define MAX_M 10000

using namespace std;

unsigned n, m, size;
char str[MAX_N + 5], pattern[MAX_N + 5];
unsigned pi[MAX_M + 2];
// unsigned psi[MAX_M + 2];

//-------------------------------------------------------------
void compressPi() 
// compress pi[] and create two new arrays: psi[] and omega[]
// description in README
{
  // Initialize the first values
  // 0 is the first state. At this step it receives 2 sons
#if 0
  psi[0] = 0;
  psi[1] = 0;
#endif
  //degree[0] = 2;
  // Compute pi and psi
  unsigned k = 0;
  for (unsigned q = 1; q < m; ++q) {
    // Compute the normal pi
    // If I'm not wrong, it could be also done with psi!
	  while ((k > 0) && (pattern[q] != pattern[k])) {
      k = pi[k - 1];
    }
    if (pattern[q] == pattern[k]) {
      k++;
    }
    pi[q] = k;

#if 0
		// Compress possbile path
		// If no jump, connect directly to 0
		if (pi[q] == 0) {
      psi[q + 1] = 0;
		} else if (pattern[q + 1] == pattern[pi[q]]) {
			// Try to hang the edge (q, pi[q]) at the root of pi[q]
      psi[q + 1] = psi[pi[q]];
		} else {
			// Put the edge back where it was
			psi[q + 1] = pi[q];
		}
		// build the graph of psi, by counting the degree of each node
		//degree[psi[q + 1]]++;
#endif
    }
  
#if 0
  // Alloc the graph and reset the degrees to 0
  for (unsigned q = 0; q < m; ++q) {
    if (degree[q])
      edges[q] = (unsigned*)calloc(degree[q], sizeof(unsigned));
    degree[q] = 0;
  }
  // Compute the graph
  for (unsigned q = 1; q <= m; ++q) {
    edges[psi[q]][degree[psi[q]]++] = q; 
  }

#if 0
  cerr << "Debug" << endl;
  for (unsigned index = 0; index < m; ++index) {
    cerr << "Main node : " << index << " ";
    for (unsigned ptr = 0; ptr < degree[index]; ++ptr) {
      cerr << edges[index][ptr] << " ";
    }
    cerr << endl;
  }
  cerr << endl;
#endif
  
  // Compute omega[] with dfs
  unordered_map<char, unsigned> stackTable;
  set<unsigned> setOfStates;
  dfs(0, stackTable, setOfStates);
  assert(stackTable.empty());
  assert(setOfStates.empty());

#if 0
  cerr << "Debug" << endl;
  for (unsigned index = 0; index <= m; ++index) {
    cerr << index << " with " << pattern[index] << " psi = " << psi[index] << " and omega = " << omega[index] << endl;
  }
  cerr << endl;
#endif

  // delete the graph
  for (unsigned index = 0; index < m; ++index)
    if (degree[index])
      free(edges[index]);
#endif
}
//-------------------------------------------------------------
static unsigned hyperKmp() {
	if (m > n) {
		return 0;
	}
	
	// Create pi[], psi[] and omega[]
	compressPi();
  
  unsigned q = 0; // current state
	//unsigned maximum = 0; // to test how many loop steps are maximal done
	//unsigned sum = 0;
	unsigned countMatches = 0;
	for (unsigned index = 0; index < n; ++index) {
		// Search only on psi now
#if 0
    unsigned loopsCtr = 0;
#if 1
    // lastHalt represents the last state which should be discovered (starting from q)
		unsigned lastHalt = omega[q];
		while ((q > lastHalt) && (str[index] != pattern[q])) {
			q = psi[q];
      loopsCtr++;
		}
#else
  while ((q > 0) && (str[index] != pattern[q])) {
    q = pi[q - 1];
    loopsCtr++;
  }
#endif

#if 0
    //cerr << q << " vs " << after << endl;
    if (q != after) {
      cerr << "assert : at " << index << " " << q << " vs " << after << endl;
      assert(0);
    }
#endif
    // Compute the average and the maximum loop steps
    sum += loopsCtr;
    if (loopsCtr > maximum) 
      maximum = loopsCtr;
#else
    
#if 0
    // lastHalt represents the last state which should be discovered (starting from q)
		//unsigned lastHalt = omega[q];
		while ((q > 0) && (str[index] != pattern[q])) {
			q = psi[q];
    }
#else
  while ((q > 0) && (str[index] != pattern[q]))
    q = pi[q - 1];
#endif
  
#endif
		if (str[index] == pattern[q]) {
			++q;
		}
		// Found?
		countMatches += (q == m);
	}
	return countMatches;
	//cerr << "sum = " << sum << " and max loopsCtr = " << maximum << endl;
}
//-------------------------------------------------------------
int main(int argc, char** argv) {
    ifstream cin;
#if 0
  if (argc < 2) {
    cerr << "Usage: " << argv[0] << " file " << endl;
    return 0;
  }
  in.open(argv[1]);
#else
  cin.open("ahocorasick.in");
  ofstream out("ahocorasick.out");
  // cin.open(1 ? "multest.in" : "test/grader_test30.in");
#endif
  cin >> str >> size;
  n = strlen(str);
  while (size--) {
    cin >> pattern;
    m = strlen(pattern);
    pattern[m] = '#';
    out << hyperKmp() << endl;
  }
  return 0;
}