HDU ACM 3065 病毒袭击持续中->AC自动机

HDU ACM 3065 病毒侵袭持续中->AC自动机

分析:AC自动机,注意该題是找单词出现的次数,因此在查询过程中不做限制,即查询过的不标记,因为所有出现情况都要计数,刚好利用了AC自动机特有fail指针。


#include<iostream>
#include<queue>
using namespace std;

char b[2000002];
#define LETTER_COUNT 128
int coun[1001];
char a[1001][60];

class AC_Automation
{
private:
	struct Node
	{
		Node* fail;                  //失败指针
		Node* next[LETTER_COUNT];  //Tire树节点的子节点
		int id;                    //每个病毒的最后一个节点,为病毒id
		Node()
		{
			fail=NULL;
			id=-1;
			memset(next,NULL,sizeof(next));
		}
	};
	Node* m_sroot;

	void Delete(Node* p);
public:
	AC_Automation(){ m_sroot=(Node*)new Node();}
	~AC_Automation(){ Delete(m_sroot);}

	void AddWord(char* str,int id);      //添加病毒特征码,id为病毒id
	void Build_AC_Automation();
	int GetMatchingCount(char* str);
};

int AC_Automation::GetMatchingCount(char* str)
{
	int cnt=0,index;
	Node* p,*temp;

	p=m_sroot;
	while(*str)
	{
		index=*str-' ';
		while(p->next[index]==NULL && p!=m_sroot) p=p->fail;
		p=p->next[index];
		p=(p==NULL)?m_sroot:p;

		temp=p;
		while(temp!=m_sroot)    //这里不做限制,因为任何情况都要匹配到
		{
			if(temp->id>=0) coun[temp->id]++;
			temp=temp->fail;
		}
		str++;
	}
	return cnt;
}

void AC_Automation::Delete(Node* p)
{
	for(int i=0;i<LETTER_COUNT;i++)
		if(p->next[i]!=NULL)
			Delete(p->next[i]);
	delete p;
}

void AC_Automation::Build_AC_Automation()
{
	int i;
	Node *temp,*p;
	queue<Node*> q; //队列,用于BFS,建立失败指针

	m_sroot->fail=NULL;
	q.push(m_sroot);
	while(!q.empty())
	{
		temp=q.front();
		q.pop();
		p=NULL;
		for(i=0;i<LETTER_COUNT;i++)
		{
			if(temp->next[i]!=NULL)
			{
				if(temp==m_sroot) temp->next[i]->fail=m_sroot;
				else
				{
					p=temp->fail;
					while(p!=NULL)
					{
						if(p->next[i]!=NULL)
						{
							temp->next[i]->fail=p->next[i];
							break;
						}
						p=p->fail;
					}
					if(p==NULL) temp->next[i]->fail=m_sroot;
				}
				q.push(temp->next[i]);        //子节点如队列
			}
		}
	}
}

void AC_Automation::AddWord(char* str,int id)
{
	Node* p=m_sroot;
	int index;

	while(*str)
	{
		index=*str-' ';
		if(p->next[index]==NULL) p->next[index]=(Node*)new Node();
		p=p->next[index];
		str++;
	}
	p->id=id;
}

void OutPut(int n)
{
	int i;

	for(i=0;i<n;i++)
		if(coun[i])
			cout<<a[i]<<": "<<coun[i]<<endl;

}

int main()
{
	int N,i;

	while(cin>>N)
	{
		AC_Automation ac_tuto;
    	for(i=0;i<N;i++)
		{
     		cin>>a[i];
    		ac_tuto.AddWord(a[i],i);
		}
    	ac_tuto.Build_AC_Automation();
  
		memset(coun,0,sizeof(coun));
		cin>>b;
		ac_tuto.GetMatchingCount(b);
		OutPut(N);
	}
	return 0;
}