hdu 2896 病毒侵袭 -- AC自动机

/*
寻找都有哪些子串
不能保证是字母或数字,所以子节点有差不多130个
*/
#include <iostream> 
#include<string.h>
#include<stdlib.h>
using namespace std; 
  
int biaoshi[510];
const int kind = 130; 
int dulist[10];
struct node{  
    node *fail;       //失败指针
    node *next[kind]; 
    int count;        //是否为该单词的最后一个节点
    node(){           //构造函数初始化
        fail=NULL; 
        count=0; 
        memset(next,NULL,sizeof(next)); 
    } 
}*q[5000000];          //队列,方便用于bfs构造失败指针
char keyword[510];     //输入的单词
char str[1000010];    //模式串
int head,tail;        //队列的头尾指针
  
void insert(char *str,node *root,int no){ 
    node *p=root; 
    int i=0,index;  
    while(str[i]){ 
        index=str[i]-31; 
        if(p->next[index]==NULL) p->next[index]=new node();  
        p=p->next[index];
        i++;
    } 
    p->count=no;//初始化为0,++后为1,表示是一个单词的结尾
} 
void build_ac_automation(node *root)
{
    int i;
    root->fail=NULL; 
    q[head++]=root; 
    while(head!=tail)
	{ 
        node *temp=q[tail++];//拿到一个节点
        node *p=NULL; 
        for(i=0;i<130;i++)
		{ 
            if(temp->next[i]!=NULL)//若其i孩子非空
			{ 
                if(temp==root) //他自己是头,其孩子的失败指针指向头
					temp->next[i]->fail=root;                 
                else{ //普通节点
                    p=temp->fail; //指向自己的失败指针
                    while(p!=NULL)
					{  
                        if(p->next[i]!=NULL)//失败指针有i孩子
						{ 
                            temp->next[i]->fail=p->next[i]; //当前节点的i孩子的失败指针指向失败指针的i孩子,然后跳出
                            break; 
                        } 
                        p=p->fail; //继续找失败指针
                    } 
                    if(p==NULL) //若失败指针为空
						temp->next[i]->fail=root; //当前节点的i孩子的失败指针指向头
                } 
                q[head++]=temp->next[i];  //进去的都是定义过失败指针的,故此过程是给其孩子定义失败指针
            } 
        }   
    } 
} 
int query(node *root)
{ 
    int i=0,cnt=0,index,len=strlen(str); 
    node *p=root;  
    while(str[i])
	{  
        index=str[i]-31;  //计算孩子的位置
        while(p->next[index]==NULL && p!=root) 
			p=p->fail; //若没有i孩子节点,通过失败指针找与这之前相同的有i孩子的节点
        p=p->next[index]; //指向其i孩子
        p=(p==NULL)?root:p; 
        node *temp=p; 
        while(temp!=root && temp->count)
		{ 
			if(temp->count&&!biaoshi[temp->count])//主要是改这里
			{
				cnt++;
				biaoshi[temp->count]=1;
			}
            temp=temp->fail; 
        } 
        i++;                 
    }    
    return cnt; 
} 
int cmp(const void *a,const void *b)
{
	int *c=(int*)a,*d=(int*)b;
	return *c-*d;
}
void print(int ji,int na,int n)
{

	printf("web %d:",na);
	for(int i=1;i<=n;++i)
	{
		if(biaoshi[i])
		{
		printf(" %d",i);
		}
	}
	printf("\n");
}
int main(){ 
    int n,t,i,j=0; 
    while(scanf("%d",&n)!=EOF)
	{  
        head=tail=0; 
        node *root=new node(); 
      
        getchar(); 
        for(i=1;i<=n;i++)
		{
            gets(keyword); 
            insert(keyword,root,i); 
        } 
        build_ac_automation(root); 
		scanf("%d",&t);
		for(i=1;i<=t;++i)
		{
			memset(biaoshi,0,sizeof(biaoshi));
			scanf("%s",str); 
			int ge=query(root);
			if(ge)
			{
				print(ge,i,n);
				j++;
			}
		}
		printf("total: %d\n",j);
    } 
    return 0; 
}


posted @ 2013-03-30 16:19  xinyuyuanm  阅读(151)  评论(0编辑  收藏  举报