zoukankan      html  css  js  c++  java
  • [POI2000]病毒

    [POI2000] 病毒


    1.题目

    题目描述

    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

    示例:例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

    任务:请写一个程序:

    1.在文本文件WIR.IN中读入病毒代码;

    2.判断是否存在一个无限长的安全代码;

    3.将结果输出到文件WIR.OUT中。

    输入输出格式

    输入格式:

    在文本文件WIR.IN的第一行包括一个整数(n(n leqslant 2000)) ,表示病毒代码段的数目。以下的(n)行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

    输出格式:

    在文本文件WIR.OUT的第一行输出一个单词:

    TAK——假如存在这样的代码;

    NIE——如果不存在。

    输入输出样例

    输入样例#1:

    3
    01 
    11 
    00000
    

    输出样例#1:

    NIE
    

    2.题解

    此题考虑将病毒串构建成一个AC自动机;病毒代码即会与某个串匹配,而安全代码则不会。所以构建好AC自动机后沿(fail)指针跳转,直到找到一个环即可。找环的操作可以使用dfs完成。

    代码:

    #include <algorithm>
    #include <cstdio>
    const int MAXN = 2010;
    const int MAXLEN = 30010;
    struct Node{
        int fail;
        int next[2];
        bool exist;
    }tree[MAXLEN];
    struct QUEUE{
        int head, tail;
        int a[MAXLEN];
        QUEUE() {head = tail = 0;}
        bool empty() {return (head == tail);}
        void push(int x) {a[++tail] = x;}
        int pop() {return (a[++head]);}
        void clean() {head = tail = 0;}
    }que;
    int n, top;
    char str[MAXLEN];
    bool vis[MAXLEN], nowvis[MAXLEN];
    inline void insert() {
        int iter(0), tmp(0), now(0);
        for (; str[iter]; ++iter) {
            tmp = str[iter] - '0';
            if(!tree[now].next[tmp]) tree[now].next[tmp] = ++top;
            now = tree[now].next[tmp];
        }
        tree[now].exist = true;
        return ;
    }
    inline void Make_fail() {
        int now(0), tmp(0);
        if(tree[0].next[0]) tree[tree[0].next[0]].fail = 0, que.push(tree[0].next[0]);
        if(tree[0].next[1]) tree[tree[0].next[1]].fail = 0, que.push(tree[0].next[1]);
        while(!que.empty()) {
            now = que.pop();
            if((tmp = tree[now].next[0])) {
                tree[tmp].fail = tree[tree[now].fail].next[0];
                que.push(tmp);
                if(tree[tree[tmp].fail].exist)
                    tree[tmp].exist = true;
            }
            else tree[now].next[0] = tree[tree[now].fail].next[0];
            if((tmp = tree[now].next[1])) {
                tree[tmp].fail = tree[tree[now].fail].next[1];
                que.push(tmp);
                if(tree[tree[tmp].fail].exist)
                    tree[tmp].exist = true;
            }
            else tree[now].next[1] = tree[tree[now].fail].next[1];
        }
    }
    inline void dfs(int now) {
        nowvis[now] = true; int tmp(0);
        for (int i = 0; i <= 1; ++i) {
            if(nowvis[(tmp = tree[now].next[i])]) {
                printf("TAK
    "); std::exit(0);
            }
            else if(!tree[tmp].exist && !vis[tmp]) {
    /*在这里,因为我们在求Fail指针的时候将此节点的空儿子修改为其Fail节点的儿子,即失配的时候一步即可转移到位,所以这里我们两个子节点都要dfs。这既保证了有Fail指针一定跳跃,也保证了它的实际子节点也可以搜索到。*/
                vis[tmp] = true;
                dfs(tmp);
            }
        }
        nowvis[now] = false;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%s", str);
            insert();
        }
        Make_fail();
        dfs(0);
        printf("NIE
    ");
        return 0;
    }
    

    附题目传送门:传送门

  • 相关阅读:
    python---装饰器用法小结
    python---mysql事务
    python---sql语句集体更改数据
    python多继承中的深度优先与广度优先
    python---copy
    vue 主次页面区分
    css 过渡动画
    android web外壳
    cordova 打包 守护进程无法启动
    JavaScript 原生控制元素添加删除
  • 原文地址:https://www.cnblogs.com/manziqi/p/9264887.html
Copyright © 2011-2022 走看看