版权声明:欢迎转载欢迎评论! 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;
}