bzoj2938:[Poi2000]病毒

传送门

想到一个点上这个题目就没了:如果可以找到,那么必然是trie树上不经过病毒节点的一个环
接下来定义“病毒节点”:病毒节点就是病毒代码的最后一个字符,但是直接这样写会错,显然存在一个病毒代码是另一个病毒代码的子串的情况,那么一个病毒代码中就可能存在多个这样的病毒节点,怎么寻找呢?这就是一个多串匹配的问题了,AC自动机可以解决。
找环就用dfs就好了,记住一定要每个节点如果已经被尝试过就没有用了,再次尝试也找不到路径了,bzoj卡了不考虑这个的代码
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
void read(int &x) {
	char ch; bool ok;
	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=3e4+10;queue<int>q;bool ed[maxn],vis[maxn],used[maxn];
int fail[maxn],n,rt=1,id=1,ch[maxn][2],ans;char s[maxn];
void insert(char *s,int d)
{
	int len=strlen(s+1);rt=1;
	for(rg int i=1;i<=len;i++)
	{
		int now=s[i]-'0';
		if(!ch[rt][now])ch[rt][now]=++id;
		rt=ch[rt][now];
	}
	ed[rt]=1;
}
void bfs()
{
	q.push(1);
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(rg int i=0;i<2;i++)
		{
			if(!ch[x][i]){ch[x][i]=fail[x]?ch[fail[x]][i]:1;continue;}
			int j=fail[x],z=ch[x][i];q.push(z);
			while(j&&!ch[j][i])j=fail[j];
			if(j)fail[z]=ch[j][i];
			else fail[z]=1;
			ed[z]|=ed[fail[z]];
		}
	}
}
bool solve(int x)
{
	vis[x]=1;
	for(rg int i=0;i<2;i++)
	{
		if(vis[ch[x][i]])return 1;
		if(ed[ch[x][i]]||used[ch[x][i]])continue;
		used[ch[x][i]]=1;
		if(solve(ch[x][i]))return 1;
	}
	vis[x]=0;
	return 0;
}
int main()
{
	read(n);
	for(rg int i=1;i<=n;i++)scanf("%s",s+1),insert(s,i);
	bfs();if(solve(1))printf("TAK\n");else printf("NIE\n");
}
posted @ 2019-02-25 21:03  蒟蒻--lichenxi  阅读(97)  评论(0编辑  收藏  举报