zoukankan      html  css  js  c++  java
  • 【BZOJ2938】[Poi2000]病毒 AC自动机+DFS

    【BZOJ2938】[Poi2000]病毒

    Description

    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
    示例:
    例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
    任务:
    请写一个程序:
    l         读入病毒代码;
    l         判断是否存在一个无限长的安全代码;
    l         将结果输出

    Input

    第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

    Output

    你应在在文本文件WIN.OUT的第一行输出一个单词:
    l         TAK——假如存在这样的代码;
    l         NIE——如果不存在。

    Sample Input

    3
    01
    11
    00000

    Sample Output

    NIE

    题解:先用AC自动机把fail合并到儿子节点上,删去单词的结束点,然后用DFS看一下Trie树里有没有环就行了,有环就是TAK

    也可以用拓补排序判环,但是比较难搞,因为不知道入度什么时候为0

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int maxn=30010;
    struct node
    {
        int ch[2],fail,cnt;
    }p[maxn];
    int n,tot,ans;
    char str[maxn];
    int vis[maxn],ins[maxn];
    queue<int> q;
    void dfs(int x)
    {
        int i;
        ins[x]=vis[x]=1;
        for(i=0;i<=1;i++)
        {
            if(p[p[x].ch[i]].cnt)    continue;
            if(!vis[p[x].ch[i]])    dfs(p[x].ch[i]);
            else if(ins[p[x].ch[i]])    ans=1;
        }
        ins[x]=0;
    }
    int main()
    {
        scanf("%d",&n);
        int i,j,k,u,t;
        tot=1;
        for(i=1;i<=n;i++)
        {
            scanf("%s",str);
            k=strlen(str);
            u=1;
            for(j=0;j<k;j++)
            {
                if(!p[u].ch[str[j]-'0'])    p[u].ch[str[j]-'0']=++tot;
                u=p[u].ch[str[j]-'0'];
            }
            p[u].cnt=1;
        }
        q.push(1);
        while(!q.empty())
        {
            u=q.front(),q.pop();
            for(i=0;i<=1;i++)
            {
                if(p[u].ch[i])
                {
                    q.push(p[u].ch[i]);
                    if(u==1)    p[p[u].ch[i]].fail=1;
                    else p[p[u].ch[i]].fail=p[p[u].fail].ch[i];
                    p[p[u].ch[i]].cnt|=p[p[p[u].fail].ch[i]].cnt;
                }
                else
                {
                    if(u==1)    p[u].ch[i]=1;
                    else    p[u].ch[i]=p[p[u].fail].ch[i];
                }
            }
        }
        dfs(1);
        if(ans==1)    printf("TAK");
        else    printf("NIE");
        return 0;
    }
  • 相关阅读:
    upc组队赛16 Melody【签到水】
    upc组队赛16 WTMGB【模拟】
    upc组队赛15 Supreme Number【打表】
    upc组队赛15 Lattice's basics in digital electronics【模拟】
    upc组队赛15 Made In Heaven【第K短路 A*】
    upc组队赛14 As rich as Crassus【扩展中国剩余定理】
    upc组队赛14 Floating-Point Hazard【求导】
    upc组队赛14 Communication【并查集+floyd /Tarjan】
    upc组队赛14 Bus stop【签到水】
    2018/12/7 数据库事务和分布式事务
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6265667.html
Copyright © 2011-2022 走看看