P2444 [POI2000]病毒------ac自动机+dfs

梦想与她 提交于 2019-12-02 15:01:34

原题

这里有个技巧,就是关于怎么找到无限长的字符串,其实就是在ac机上寻找环,这个环中不允许有任何模板字符串的fail指针指着环的人任何一节。
所以用pos存是否该字符串存在模板字符串的,如果pos[fail[x]]是1,那么pos[x]必是1,因为在fail树中,父树永远出现在子树中,而且是后缀。

#include<bits/stdc++.h>
using namespace std;
const int MX=1e5+9;
int n,tot=0,pos[MX],t[MX<<2][2],fail[MX];
char s[MX];

void inst(){
    int now=0;
    for( int i=0 ; s[i] ; i++ ){
        int a=s[i]-'0';
        if( !t[now][a] )
            t[now][a]=++tot;
        now=t[now][a];
    }
    pos[now]=1;
}

void build(){
    queue<int> que;
    for( int i=0 ; i<=1 ; i++ )
        if( t[0][i] )
            que.push(t[0][i]);
    while( !que.empty() ){
        int now=que.front();
        que.pop();
        for( int i=0 ; i<=1 ; i++ ){
            if( t[now][i] ){
                que.push(t[now][i]);
                fail[t[now][i]]=t[fail[now]][i];
                pos[t[now][i]]|=pos[fail[t[now][i]]];   // 放这2个地方都可以,不过放下面会一个点多次赋值,
            }
            else
                t[now][i]=t[fail[now]][i];      
         //   pos[t[now][i]]|=pos[fail[t[now][i]]];
        }
    }
    return ;
}

int vis[MX],v[MX],falg=0;

void dfs(int u){
    for( int i=0 ; i<=1 ; i++ ){
        if( !pos[t[u][i]] ){
            if( v[t[u][i]] ){
                if( vis[t[u][i]] ){
                    falg=1;
                    return ;
                }
            }
            else{
                vis[t[u][i]]=1,v[u]=1;   // v是为了防止走已经走过的点,否则tle,因为从多个节点走可能走到同于一个节点,这样就导致重复走了
                dfs(t[u][i]);
                vis[t[u][i]]=0;
            }
        }
    }
}

int main()
{
    freopen("input.txt","r",stdin);
    scanf("%d",&n);
    for( int i=1 ; i<=n ; i++ ){
        scanf("%s",s);
        inst();
    }
    build();
    dfs(0);
    if( falg )
        printf("TAK\n");
    else
        printf("NIE\n");
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!