洛谷 P2444 [POI2000]病毒

版权声明:欢迎转载欢迎评论! https://blog.csdn.net/rabbit_ZAR/article/details/85324664

题目:病毒


思路:

首先把所有病毒代码建成trie。

然后建出fail指针,顺便完成AC自动机的优化。

然后分析样例可以获得这样一棵trie图——

3
01 
11 
00000

其中黑边是trie的正常边,绿边是在处理AC自动机时连上的优化边,红边是fail指针。

节点内部的数是节点权值,旁边的是节点编号。

可以知道,一个无限的文本串,在AC自动机匹配的过程中一定会“死循环”,即存在环状的匹配。

这在这颗trie中的体现就是存在从根节点开始的环。

要注意,这里的环是由绿边和黑边构成的,即不考虑走fail指针(想一想,为什么)。

由于这个环状匹配不存在病毒,所以我们要找的环中一定不存在一个病毒的结尾。

且考虑AC自动机执行的过程,要从根节点开始匹配。


代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 2000
#define maxm 30000
#define read(x) scanf("%d",&x)

struct Trie {
	int ch[maxm+5][2];
	int cnt,v[maxm*2+5];
	int fl[maxm*2+5];
	
	void insert(char* x) {
		int u=0,len=strlen(x);
		for(int i=0; i<len; i++) {
			int y=x[i]-'0';
			if(!ch[u][y]) ch[u][y]=++cnt;
			u=ch[u][y];
		}
		v[u]=true;
	}

	void make_fl() {
		queue<int> que;
		if(ch[0][0]) que.push(ch[0][0]);
		if(ch[0][1]) que.push(ch[0][1]);

		while(!que.empty()) {
			int u=que.front();
			que.pop();
			for(int i=0; i<=1; i++)
				if(!ch[u][i]) ch[u][i]=ch[fl[u]][i];
				else {
					que.push(ch[u][i]);
					fl[ch[u][i]]=ch[fl[u]][i];
					if(v[fl[ch[u][i]]]) v[ch[u][i]]=true;
				}
		}
	}
} ac ;

int n;

bool vis[maxm*2+5],use[maxm*2+5];

bool dfs(int x) {
	vis[x]=true;
	for(int i=0;i<=1;i++) {
		int y=ac.ch[x][i];
		if(!y) continue;
		if(vis[y]) return true;
		if(use[y]||ac.v[y]) continue;
		use[y]=true;
		if(dfs(y)) return true;
	}
	vis[x]=false;
	return false;
}

int main() {
	read(n);
	for(int i=1; i<=n; i++) {
		char x[maxn+5];
		scanf("%s",x);
		ac.insert(x);
	}
	ac.make_fl();
	
	bool ans=dfs(0);
	if(ans) printf("TAK");
	else printf("NIE");
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/rabbit_ZAR/article/details/85324664