BZOJ 2938 [Poi2000]病毒(AC自动机)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2938

 

【题目大意】

  给出一些病毒串,问是否存在不包含任何病毒串的无限长的字符串

 

【题解】

  首先我们对病毒串建立AC自动机,如果我们能够在AC自动机上无限跑但是不成功匹配,
  说明就存在这样的安全串,我们在AC自动机上做搜索,
  若存在不经过match的环,那就是TAK,否则就是NIE。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring> 
using namespace std;
const int N=30010;
namespace AC_DFA{
    const int Csize=2; 
    int tot,son[N][Csize],sum[N],fail[N],q[N],match[N];
    void Initialize(){
        memset(match,0,sizeof(int)*(tot+1)); 
        memset(fail,0,sizeof(int)*(tot+1));
        for(int i=0;i<=tot;i++)for(int j=0;j<Csize;j++)son[i][j]=0;
        tot=0; fail[0]=-1;
    }
    inline int Tr(char ch){return ch-'0';}
    int Insert(char *s){
        int x=0;
        for(int l=strlen(s),i=0,w;i<l;i++){
            if(!son[x][w=Tr(s[i])]){
                son[x][w]=++tot;
            }x=son[x][w]; 
        }sum[x]++;
        return x;
    }
    void MakeFail(){
        int h=1,t=0,i,j,x=0;
        for(i=0;i<Csize;i++)if(son[0][i])q[++t]=son[0][i];
        while(h<=t)for(x=q[h++],i=0;i<Csize;i++)
        if(son[x][i]){
            fail[son[x][i]]=son[fail[x]][i],q[++t]=son[x][i];
            match[son[x][i]]=sum[son[x][i]]?son[x][i]:match[fail[son[x][i]]];
        }else son[x][i]=son[fail[x]][i];
    }
}
using namespace AC_DFA;
int inq[N],vis[N];
bool dfs(int x){
    inq[x]=1;
    for(int i=0;i<Csize;i++){
        int y=son[x][i];
        if(inq[y])return 1;
        if(vis[y]||match[y])continue;
        vis[y]=1;
        if(dfs(y))return 1;
    }inq[x]=0;
    return 0;
}
int n;
char s[N];
int main(){
    Initialize(); 
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        Insert(s);
    }MakeFail();
    if(dfs(0))puts("TAK");
    else puts("NIE");
    return 0;
}
posted @ 2017-08-14 16:22  forever97  阅读(213)  评论(0编辑  收藏  举报