【hdu2896】【AC自动机】病毒侵袭

16 篇文章 0 订阅

同样是一道很裸的AC自动机,统计哪些特征码出现在网站的源码上,匹配成功时不要将val赋值为0,因为后面还有文本串要匹配,另外要注意编号需要从小到大输出。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100000 + 10;
const int maxm = 500 + 10;
const int maxlen = 10000 + 10;
const int child_num = 128;
int n,m,tot = 0,sz = 1;
char temp[maxlen],exp[maxlen];
class ACAutumaton
{
private:
	int chd[maxn][child_num];
	int fail[maxn],val[maxn];
	int ans[maxm];
	int Q[maxn];
	int ID[128];
	int cnt;
public:
	void Reset()
	{
		memset(ans,0,sizeof(ans));
		cnt = 0;
	}
	void Insert(char *a,int key)
	{
		int p = 0;
		for(; *a ;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;
	}
	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];
				}
				else v = chd[ fail[u] ][i];
			}
		}
	}
	void work(char *T)
	{
		int n = strlen(T);
		int x = 0;
		for(int i = 0;i < n;i++)
		{
			x = chd[x][(int)T[i]];
			int tmp = x;
			while(tmp && val[tmp] != 0)
			{
				ans[cnt++] = val[tmp];
				tmp = fail[tmp];
			}
		}
	}
	void print(int step)
	{
		if(cnt)
		{
			sort(ans,ans + cnt);
			tot++;
			printf("web %d: ",step);
			for(int i = 0;i < cnt - 1;i++)
			{
				printf("%d ",ans[i]);
			}
			printf("%d\n",ans[cnt-1]);
		}
	}
}AC;

void init()
{
	freopen("hdu2896.in","r",stdin);
	freopen("hdu2896.out","w",stdout);
}

void readdata()
{
	AC.Reset();
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
	{
		scanf("%s",temp);
		AC.Insert(temp,i);
	}
	AC.Construct();
}

void solve()
{
	scanf("%d",&m);
	for(int i = 1;i <= m;i++)
	{
		AC.Reset();
		scanf("%s",exp);
		AC.work(exp);
		AC.print(i);
	}
	printf("total: %d\n",tot);
}

int main()
{
	init();
	readdata();
	solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值