BZOJ2938: [Poi2000]病毒
【传送门:BZOJ2938】
简要题意:
给出n个01串,判断是否存在一个无限长的01串不包含任意一个给出的01串
题解:
AC自动机构造fail指针,画一下图可以知道
如果在字典树中找到环,就可以找到一个无限长的01串
注意:当一个点有一个儿子不存在时,可以将fail边当作儿子边来使用,这样子就可以直接dfs找环了
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<queue> using namespace std; struct trie { int c[2],s,fail; trie() { s=0;fail=0; c[0]=c[1]=-1; } }t[31000];int tot; char st[31000]; void bt() { int len=strlen(st+1),x=0; for(int i=1;i<=len;i++) { int y=st[i]-'0'; if(t[x].c[y]==-1) t[x].c[y]=++tot; x=t[x].c[y]; } t[x].s=1; } queue<int> q; void bfs() { q.push(0); while(q.empty()==0) { int x=q.front();q.pop(); for(int i=0;i<=1;i++) { int son=t[x].c[i]; if(son==-1) { t[x].c[i]=t[t[x].fail].c[i]; continue; } if(t[x].s==1) t[son].s=1; if(x==0) t[son].fail=0; else { int j=t[x].fail; while(j!=0&&t[j].c[i]==-1) j=t[j].fail; t[son].fail=max(0,t[j].c[i]); if(t[t[son].fail].s==1) t[son].s=1; } q.push(son); } } } bool v[31000],bo[31000]; bool dfs(int x) { v[x]=true;bo[x]=true; for(int i=0;i<=1;i++) { int y=t[x].c[i]; if(v[y]==true) return true; if(y==-1||t[y].s==1||bo[y]==true) continue; if(dfs(y)==true) return true; } v[x]=false; return false; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",st+1); bt(); } bfs(); memset(bo,false,sizeof(bo)); memset(v,false,sizeof(v)); if(dfs(0)==true) printf("TAK\n"); else printf("NIE\n"); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚