hdu 2896 病毒入侵 ac自动机入门 附加一组数据

病毒侵袭


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12989    Accepted Submission(s): 3346




Problem Description
当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻。。。。在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~
但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒。小t不幸成为受害者之一。小t如此生气,他决定要把世界上所有带病毒的网站都找出来。当然,谁都知道这是不可能的。小t却执意要完成这不能的任务,他说:“子子孙孙无穷匮也!”(愚公后继有人了)。
万事开头难,小t收集了好多病毒的特征码,又收集了一批诡异网站的源码,他想知道这些网站中哪些是有病毒的,又是带了怎样的病毒呢?顺便还想知道他到底收集了多少带病毒的网站。这时候他却不知道何从下手了。所以想请大家帮帮忙。小t又是个急性子哦,所以解决问题越快越好哦~~
 


Input
第一行,一个整数N(1<=N<=500),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在20—200之间。
每个病毒都有一个编号,依此为1—N。
不同编号的病毒特征码不会相同。
在这之后一行,有一个整数M(1<=M<=1000),表示网站数。
接下来M行,每行表示一个网站源码,源码字符串长度在7000—10000之间。
每个网站都有一个编号,依此为1—M。
以上字符串中字符都是ASCII码可见字符(不包括回车)。
 


Output
依次按如下格式输出按网站编号从小到大输出,带病毒的网站编号和包含病毒编号,每行一个含毒网站信息。
web 网站编号: 病毒编号 病毒编号 …
冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。
最后一行输出统计信息,如下格式
total: 带病毒网站数
冒号后有一个空格。
 


Sample Input
3
aaa
bbb
ccc
2
aaabbbccc
bbaacc
 


Sample Output
web 1: 1 2 3
total: 1

 


入门的题。  之前模版会把在query 访问过的 cnt 改为-1。没有及时发觉,导致wa了好多次。

还有就是next数组要大点,可以直接开128 。



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map> 
 

#define LL long long
#define MIN INT_MIN
#define MAX INT_MAX
#define PI acos(-1.0)
#define FRE freopen("input.txt","r",stdin)
#define FF freopen("output.txt","w",stdout)
#define N 10005
#define M 1000005
const int kind = 130;
char ss[10010];//输入的模式串
struct node 
{
    node *fail;//失败指针
    node *next[kind];//Trie每个节点的子节点(最多26个子母)
    int cnt;//是否为该单词的最后一个节点
    node () 
	{//构造函数初始化
        fail = NULL;
        cnt = 0;
        memset(next,NULL,sizeof(next));
    };
};
char str[210];//输入的单词
vector <int > arr;
queue<node*> qq;//队列构造失败指针
//建Trie树
void BuildTree (node *root,int index) 
{
    node *p = root;
    int i = 0,id;
    while (str[i]) 
	{
        id = str[i];
        if (p->next[id] == NULL) 
            p->next[id] = new node();
        p = p->next[id];
        i++;
    }
    (p->cnt) = index;
}

/*
bfs求失败指针
设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,
他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。
如果一直走到了root都没找到,那就把失败指针指向root。
*/
void bfs(node *root) 
{
    while (!qq.empty()) qq.pop();
    int i;
    root->fail = NULL;
    qq.push(root);
	root->fail = NULL;
    node *tmp,*p;
    while (!qq.empty()) 
	{
        tmp = qq.front();
        qq.pop();
        p = NULL;
        for (i = 0; i < kind; i++) 
		{
            if (tmp->next[i] != NULL) 
			{
                p = tmp->fail;
                while (p && !p->next[i]) //p:当前点 tmp不是根  !p->next[i]:还能找到i这个字母 在
                    p = p->fail; 
                if (!p)
					tmp->next[i]->fail = root;
                else 
					tmp->next[i]->fail = p->next[i];
                qq.push(tmp->next[i]);
            }
        }
    }
}
/*
AC自动机主程序
当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root 或者 匹配到下一个字母 结束。
*/

int has[600];
int AC_run(node *root) 
{
    int i = 0,ans = 0,id;
    node *p = root;
    while (ss[i])
	{
        id = ss[i] ;
        while (!p->next[id] && p != root)//!p->next[id]  p点下面没有id字母   
            p = p->fail;
        p = p->next[id];
        if(!p) p = root;// while结束 如果上面的p 最后是根的情况下。
        node *tmp = p;
        while (tmp != root && tmp->cnt != -1) 
		{//cnt=-1 表示已经计算过
			if(tmp->cnt!=0)
			{
				ans += tmp->cnt;
				has[tmp->cnt]=1;
			}
			//tmp->cnt = -1;  //不能改
            tmp = tmp->fail;
        }
        i++;
    }
    return ans;
}

int main () 
{
    int t; 
    int n;
    while (scanf("%d",&n)!=EOF) 
	{ 
        node *root = new node();
        for(int i=1;i<=n;i++)
		{
            scanf("%s",str);
            BuildTree(root,i);
        }
        bfs(root);
		int m;
        scanf("%d",&m);
		int total=0;
		for(int i=1;i<=m;i++)
		{
			memset(has,0,sizeof has);
			scanf("%s",ss);
			if(AC_run(root))
			{
				total++;
				printf("web %d:",i);
				 
				for(int j=1;j<=n;j++)
				{
					if(has[j])
						printf(" %d",j);
				}
				puts("");
			}
		}  
		printf("total: %d\n",total);
    }
    return 0;
}
/*
2
adf
dfa
2
adffff 
adfaddafdfa 

web 1: 1
web 2: 1 2
total: 2
*/ 






你可能感兴趣的:(字符串,AC自动机)