码迷,mamicode.com
首页 > 其他好文 > 详细

[POI2000]病毒

时间:2019-07-14 21:28:36      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:选择   code   bit   无线   节点   def   trie   判断   front   

题意

给定一些字符串,问是否存在一个无限长度的字符串,使得它不包含任何一个给定的串

思路

将所有串加入AC自动机,那么我们从根节点选择的一个无线字符串显然不能经过任何一个带有end标记的节点,不然就说明其中包含了这个节点对应的字符串。

于是用fail标记建成trie图,判断trie图上面有没有一个不经过end标记的环即可

Code:

#include<bits/stdc++.h>
#define N 30005
using namespace std;
int n;
int nxt[N][2],fail[N],ndsum;
char c[N];
bool is_end[N],vis[N],st[N];

void ad(char a[])
{
    int l=strlen(a),now=0;
    for(int i=0;i<l;++i)
    {
        int pp=a[i]-'0';
        if(!nxt[now][pp]) nxt[now][pp]=++ndsum;
        now=nxt[now][pp];
    }
    is_end[now]=1;
}
void getfail()
{       
    queue<int> q;
    for(int i=0;i<2;++i) if(nxt[0][i]) q.push(nxt[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<2;++i)
        if(nxt[u][i]) fail[nxt[u][i]]=nxt[fail[u]][i],q.push(nxt[u][i]),is_end[nxt[u][i]]|=is_end[fail[nxt[u][i]]];
        else nxt[u][i]=nxt[fail[u]][i];
    }
}
bool dfs(int u)
{
    if(st[u]) return true;
    if(vis[u]) return false;
    vis[u]=st[u]=1;
    for(int i=0;i<2;++i)
    {
        if(nxt[u][i]&&!is_end[nxt[u][i]]) if(dfs(nxt[u][i])) return true;
    }
    st[u]=0;
    return false;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",c);
        ad(c);
    }
    getfail();
    memset(vis,0,sizeof(vis));
    if(dfs(0)) printf("TAK\n");
    else printf("NIE\n");
    return 0;
}

[POI2000]病毒

标签:选择   code   bit   无线   节点   def   trie   判断   front   

原文地址:https://www.cnblogs.com/Chtholly/p/11185755.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!