HDU 3065 病毒侵袭持续中

本文详细介绍了AC自动机的实现过程及应用实例。通过构建AC自动机,文章演示了如何高效地查找一组模式串在目标串中出现的次数。特别针对大写字母组成的病毒模式串进行匹配,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标串中各个模式串出现了几次

这就更简单了,都不用把out标记成false了

题目中的病毒都是大写字母这个条件应该怎么用?

#include <cstdio>
#include <cstdlib>
#include <string>
#include <climits>
#include <iostream>
#include <vector>
#include <set>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <sstream>
#include <map>
#include <cstring>
#include <queue>
using namespace std;

//MAX_NODE = StringNumber * StringLength
const int MAX_NODE = 50010;
//节点个数,一般字符形式的题26个
const int CHILD_NUM = 128;
//特定题目需要
char test[2000010];
int cnt[1010];
char vernus[1010][50];

class ACAutomaton {
private:
	//每个节点的儿子,即当前节点的状态转移
	int chd[MAX_NODE][CHILD_NUM];
	//记录题目给的关键数据
	int val[MAX_NODE];
	//传说中的fail指针
	int fail[MAX_NODE];
	//队列,用于广度优先计算fail指针
	int Q[MAX_NODE];
	//字母对应的ID
//	int ID[128];
	//已使用节点个数
	int sz;
public:
	//初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
	void Initialize() {
		fail[0] = 0;
	//	for (int i = 0 ; i < CHILD_NUM ; i ++) {
	//		ID[i+base] = i;
	//	}
	}
	//重新建树需先Reset
	void Reset() {
		memset(chd[0] , 0 , sizeof(chd[0]));
		sz = 1;
	}
	//将权值为key的字符串a插入到trie中
	void Insert(char *a,int key) {
		int p = 0;
		for ( ; *a ; a ++) {
	//		int c = ID[*a];
			int c = *a;
			if (!chd[p][c]) {
				memset(chd[sz] , 0 , sizeof(chd[sz]));
				val[sz] = 0;
				chd[p][c] = sz ++;
			}
			p = chd[p][c];
		}
		val[p] = key;
	}
	//建立AC自动机,确定每个节点的权值以及状态转移
	void Construct() {
		int *s = Q , *e = Q;
		for (int i = 0 ; i < CHILD_NUM ; i ++) {
			if (chd[0][i]) {
				fail[ chd[0][i] ] = 0;
				*e ++ = chd[0][i];
			}
		}
		while (s != e) { /*广度优先。 关键*/
			int u = *s++;
			for (int i = 0 ; i < CHILD_NUM ; i ++) {
				int &v = chd[u][i];
				if (v) {
					*e ++ = v;
					 /*当前结点的失败指针 等于 
					 父节点的失败指针指向的结点的的同个字母儿子结点的指针*/
					fail[v] = chd[ fail[u] ][i]; 
					//以下一行代码要根据题目所给val的含义来写
		//			val[v] |= val[ fail[v] ];
				} else {
					v = chd[ fail[u] ][i];
				}
			}
		}
	}
	//解题,特定题目需要
	void Work()
	{
		memset(cnt, 0, sizeof(cnt));
		int n = strlen(test);
		int p = 0;
		for(int i = 0; i < n; i++)
		{
			//int next = ID[test[i]];
			//if(!isupper(test[i]))
			//	continue;
			int next = test[i];
			int tmp = p = chd[p][next];
			while(val[tmp] != 0)
			{
				cnt[val[tmp]]++;
			//	val[tmp] = 0; 
				tmp = fail[tmp];
			}
		}
	}
}AC;

int main() {
	AC.Initialize();
	int n;
	while(scanf("%d", &n) != EOF)
	{
		AC.Reset();
		for(int i = 1; i <= n; i++)
		{
			scanf("%s", &vernus[i]);
			AC.Insert(vernus[i], i);
		}
		scanf("%s", test);
		AC.Construct();
		AC.Work();
		for(int i = 1; i <= n; i++)
		{
			if(cnt[i] > 0)
				printf("%s: %d\n", vernus[i], cnt[i]);
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值