HDU ACM 2896病毒袭击->AC自动机

HDU ACM 2896病毒侵袭->AC自动机

分析:AC自动机,套用模版,保存每个网站的病毒,然后排序输出,最后统计网站数即可。

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

int VirusID[5];
#define LETTER_COUNT 128
class AC_Automation
{
private:
	struct Node
	{
		Node* fail;                  //失败指针
		Node* next[LETTER_COUNT];  //Tire树节点的子节点
		int id;                    //每个病毒的最后一个节点,为病毒id
		int webpos;                    //记录网站的id,避免病毒被重复查找
		Node()
		{
			fail=NULL;
			webpos=id=0;
			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 id);  //查找病毒,id为网站id
};

int AC_Automation::GetMatchingCount(char* str,int id)
{
	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 && temp->webpos!=id)    //确保当前字符前面包含的所有单词都被匹配
		{
			if(temp->id) VirusID[++VirusID[0]]=temp->id;
			temp->webpos=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;             //单词的最后一个节点加1,单表新加入一个单词
}

void OutPut(int id)
{
	int i;

	sort(VirusID+1,VirusID+VirusID[0]+1);
	cout<<"web "<<id<<":";
	for(i=1;i<=VirusID[0];i++)
		cout<<" "<<VirusID[i];
	cout<<endl;
}

int main()
{
	int N,i,M;
	char a[202],b[10002];
	int sum;

	while(cin>>N)
	{
		AC_Automation ac_tuto;
		sum=0;
    	for(i=1;i<=N;i++)
		{
     		cin>>a;
    		ac_tuto.AddWord(a,i);
		}
    	ac_tuto.Build_AC_Automation();
    	cin>>M;
    	for(i=1;i<=M;i++)
		{
			VirusID[0]=0;
			cin>>b;
			ac_tuto.GetMatchingCount(b,i);
			if(VirusID[0])
			{
				OutPut(i);
				sum++;
			}
		}
		cout<<"total: "<<sum<<endl;
	}
	return 0;
}