【练习05】 AC自动机 1001 病毒侵袭

本文介绍了AC自动机在解决1001病毒侵袭问题中的应用,通过模板匹配和失配边递归,实现病毒编号的高效查找。程序采用通用模板,针对病毒编号和字符串匹配进行了优化。

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

算法思路:AC自动机。

要点:

1.val存储病毒的编号;

2.find函数中当找到一个模板后,应该顺着失配边往回走,由last数组递归判断是否还有其他的子模板能够匹配,所有找到的模板的val值保存到数组save中。

3.对save数组进行sort排序,注意输出格式,依次打印病毒编号。

4.题中要求是“可见字符”,在不超内存的情况下,sigma_size最好开到127。

//模板开始
#include <string>   
#include <vector>   
#include <algorithm>   
#include <iostream>   
#include <sstream>   
#include <fstream>   
#include <map>   
#include <set>   
#include <cstdio>   
#include <cmath>   
#include <cstdlib>   
#include <ctime>
#include <iomanip>
#include <string.h>
#include <queue>
#define SZ(x) (int(x.size()))
using namespace std;

int toInt(string s){
	istringstream sin(s); 
	int t; 
	sin>>t; 
	return t;
}
template<class T> string toString(T x){
	ostringstream sout; 
	sout<<x; 
	return sout.str();
}
typedef long long int64;
int64 toInt64(string s){
	istringstream sin(s); 
	int64 t; 
	sin>>t;
	return t;
}
template<class T> T gcd(T a, T b){ 
	if(a<0) 
		return gcd(-a, b);
	if(b<0) 
		return gcd(a, -b);
	return (b == 0)? a : gcd(b, a % b);
}
//模板结束(通用部分)

#define ifs cin

#define maxnode 100005
#define sigma_size 127

int save[maxnode];
int cnt;

struct Trie
{
	int ch[maxnode][sigma_size];
	int val[maxnode];
	int sz;
	int f[maxnode];
	int last[maxnode];
	Trie()
	{
		sz = 1;
		memset(ch[0], 0, sizeof(ch[0]));
	}
	int idx(char c)
	{
		return (int)c;
	}

	void insert(char* s, int v)
	{
		int u = 0, n = strlen(s);
		for(int i = 0; i < n; i++)
		{
			int c = idx(s[i]);
			if(!ch[u][c])
			{
				memset(ch[sz], 0, sizeof(ch[sz]));
				val[sz] = 0;
				ch[u][c] = sz++;
			}
			u = ch[u][c];
		}
		val[u] = v;
	}

	//int search(char* s, int n)
	//{
	//	int u = 0;
	//	int flag = 1;
	//	for(int i = 0; i < n; i++)
	//	{
	//		int c = idx(s[i]);
	//		if(ch[u][c] == 0)
	//		{
	//			flag = 0;
	//			break;
	//		}
	//		u = ch[u][c];
	//	}	
	//	if(flag && val[u])
	//	{
	//		return 1;
	//	}
	//	else
	//	{
	//		return 0;
	//	}
	//}

	void getFail()
	{
		queue<int> q;
		f[0] = 0;
		for(int c = 0; c < sigma_size; c++)
		{
			int u = ch[0][c];
			if(u)
			{
				f[u] = 0;
				q.push(u);
				last[u] = 0;

			}

			while(!q.empty())
			{
				int r = q.front();
				q.pop();
				for(int c = 0; c < sigma_size; c++)
				{
					int u = ch[r][c];
					if(!u)
					{
						continue;
					}
					q.push(u);
					int v = f[r];
					while(v && !ch[v][c])
					{
						v = f[v];
					}
					f[u] = ch[v][c];
					last[u] = val[f[u]] ? f[u] : last[f[u]];
				}
			}
		}
	}

	void save_all(int j)
	{
		if(j)
		{
			save_all(last[j]);
			save[cnt++] = val[j];	
		}
	}

	void find(char* T)
	{
		int n = strlen(T);
		int j = 0; 
		for(int i = 0; i < n; i++)
		{
			int c = idx(T[i]);
			while(j && !ch[j][c]) 
			{
				j = f[j];
			}
			j = ch[j][c];
			if(val[j])
			{
				save_all(j);
			}
			else
			{
				if(last[j])
				{
					save_all(last[j]);
				}
			}
		}
	}
};

Trie t;
char a[505][205];
char b[10005];
int jishu;

//【练习05】 AC自动机 1001 病毒侵袭

int main()
{
	//ifstream ifs("shuju.txt", ios::in);
	int n;
	while(ifs>>n)
	{
		for(int i = 1; i <= n; i++)
		{
			//ifs>>a[i];
			scanf("%s", &a[i]);
			t.insert(a[i], i);
		}
		t.getFail();
		
		ifs>>n;
		jishu = 0;
		for(int i = 1; i <= n; i++)
		{
			//ifs>>b;
			scanf("%s", &b);
			cnt = 0;
			memset(save, 0, sizeof(save));
			t.find(b);
			if(!save[0])
			{
				continue;
			}
			else
			{
				jishu++;
			}
			sort(save, save + cnt);
			cout<<"web "<<i<<":";
			for(int j = 0; j < cnt; j++)
			{
				cout<<" "<<save[j];
			}
			cout<<endl;
		}
		cout<<"total: "<<jishu<<endl;
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值