Cod sursa(job #865143)

Utilizator mika17Mihai Alex Ionescu mika17 Data 26 ianuarie 2013 03:53:07
Problema Aho-Corasick Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.43 kb
#include <string>
#include <cstring>
#include <vector>
#include <fstream>

class Matcher {

	struct Node {
		const static int SIGMA = 26;
		Node* g[SIGMA];
		Node* f;
		int occ;
		std::vector< int > o;
		Node() {
			memset(g,0,sizeof(g));
		}
	};
	std::vector<Node*> Q;
	Node * r;
	std::vector <std::string> dict;

public:
	Matcher(std::vector <std::string> & dict) {

		this->r = new Node();
		this->dict = dict;

		for(int i=0;i<(int)dict.size();++i) {

			Node * t = r;
			for(int j=0;j<(int)dict[i].size();++j) {
				if(t->g[ dict[i][j] - 'a' ] == NULL) {
					t->g[ dict[i][j] - 'a' ] = new Node();
				}
				t = t->g[ dict[i][j] - 'a' ];
			}

			t->o.push_back( i );
		}

		for(int i=0;i<Node::SIGMA;++i)
			if(r->g[i] == NULL)
				r->g[i] = r;
		
		this->r->f = NULL;

		for(int i=0;i<Node::SIGMA;++i) {
			if(r->g[i] != r) {
				Q.push_back(r->g[i]);
				r->g[i]->f = r;
			}
		}

		for(int k=0;k<(int)Q.size();++k) { // Q.size() keeps growing, using this trick instead of using a queue to save traversal for later
			Node * t = Q[k];

			for(int i=0;i<Node::SIGMA;++i) {
				if(t->g[i] != NULL) {
					Node* tmp = t->f;
					while(tmp->g[i] == NULL) 
						tmp = tmp->f;
					tmp = tmp->g[i];
					t->g[i]->f = tmp;
					Q.push_back(t->g[i]);
				}
			}
		}
	}

	bool match(std::string & str,std::vector<int> &res) {
		res = std::vector<int>(dict.size(),0);
		
		for(int i=Q.size() - 1;i >= 0; --i) {
			Q[i]->occ = 0;
		}

		Node *t = r;
		for(int i=0;i<(int)str.size();++i) {
			while(t->g[str[i] - 'a'] == NULL)
				t = t->f;
			t = t->g[str[i] - 'a'];
			if(t != r) t->occ++; //t can be either a pattern or a prefix of a pattern
		}

		for(int i=Q.size() - 1;i >= 0; --i) { //reverse BFS (actually now it's using the suffix links instead of forward char edges)
			if(Q[i]->f != r) Q[i]->f->occ += Q[i]->occ;
			
			for(int j=0;j<(int)Q[i]->o.size();++j) // there can be i != j such that pat[i] == pat[j]
				res[ Q[i]->o[j] ] = Q[i]->occ;
		}

		return res.size() > 0;
	}
};

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

	std::string A; fin >> A;

	int M; fin >> M;
	std::vector< std::string > dict;
	while(M--)
	{
		std::string tmp; fin >> tmp; dict.push_back(tmp);
	}

	std::vector<int> res;
	if(Matcher(dict).match(A,res))
	{
		for(int i=0;i<(int)res.size();++i) {
			fout<<res[i]<<std::endl;
		}
	}
	return 0;
}