Cod sursa(job #2445920)

Utilizator stoianmihailStoian Mihail stoianmihail Data 6 august 2019 02:28:38
Problema Potrivirea sirurilor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.18 kb
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
//---------------------------------------------------------------------------
// HyperKMP
// (c) 2019 Stoian Mihail
// - compress the pi-table to get rid of the worst-case of KMP
//---------------------------------------------------------------------------
using namespace std;
//---------------------------------------------------------------------------
#define MAX_N 2000000
#define MAX_COUNT 1000
//---------------------------------------------------------------------------
unsigned length, countMatches;
char buffer[2 * MAX_N + 5];
unsigned matches[MAX_COUNT + 1];
//---------------------------------------------------------------------------
unsigned psi[MAX_N + 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
  psi[0] = 0;
  psi[1] = 0;
  // Compute pi and psi
  unsigned k = 0, q = 1;
  const char* pattern = buffer;
  for (; pattern[q] != '\n'; ++q) {
    // Compute psi
    while ((k > 0) && (pattern[q] != pattern[k])) {
      k = psi[k];
    }
    if (pattern[q] == pattern[k]) {
      k++;
    }
    // Compress possible path
    // For understandability reasons, keep the formula like this
    psi[q + 1] = (pattern[q + 1] == pattern[k]) ? psi[k] : k;
  }
  length = q;
}
//---------------------------------------------------------------------------
void search()
// checks if the pattern can be found in str
{
  if (length == 1) {
    cerr << "Not supported by now" << endl;
    exit(0);
  }
  
  const char* str = buffer + length + 1;
  const char* pattern = buffer;
  
  char firstChar = pattern[0];
  unsigned q = 0; // current state
  unsigned index = 0;
  hyperKMPSearch : {
    if (str[index] == '\0')
      return;
    // Doesn't enter in the while anyhow
    if (!q) {
      const char* found = strchr(str + index, firstChar);
      if (!found)
        return;
      // Set the new state
      q = 1;
      index = found - str + 1;
      goto hyperKMPSearch;
    }
    
    // Now we have at least the first q chars matched
    // Get rid of 2 comparisons when the char matches
    if (str[index] != pattern[q]) {
      q = psi[q];
      while ((q > 0) && (str[index] != pattern[q]))
        q = psi[q];
      // TODO: what happens when q == 0?
      if (str[index] == pattern[q])
        ++q;
    } else {
      ++q;
    }
    
    // Found?
    if (q == length) {
      if ((++countMatches) <= MAX_COUNT) {
        matches[countMatches - 1] = index - length + 1;
      }
    }
    ++index;
    goto hyperKMPSearch;
  }
}
//---------------------------------------------------------------------------
int main(int argv, char** argc) {
  FILE *in;
#if 0
  in = fopen(argc[1], "r");
#else
  in = fopen("strmatch.in", "r");
#endif
  size_t essen = fread(buffer, 1, 2 * MAX_N + 5, in);
  fclose(in);
  
  compressPi();
  search();
  
  std::ofstream out("strmatch.out");
  out << countMatches << endl;
  unsigned lim = (countMatches < MAX_COUNT) ? countMatches : MAX_COUNT;
  for (unsigned index = 0; index < lim; ++index) 
    out << matches[index] << " ";
  out << endl;
  out.close();
  return 0;
}