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;
}

 

posted @ 2018-09-29 16:40  Star_Feel  阅读(196)  评论(0编辑  收藏  举报