zoukankan      html  css  js  c++  java
  • 洛谷2444:病毒

    洛谷2444:病毒

    题意:

    • 有n个二进制字符串,称为病毒。
    • 构造一个二进制字符串,使得没有任何一个病毒出现在这个构造的二进制字符串中。
    • 回答是否可以构造这样一个字符串。

    思路:

    • AC自动机。
    • AC自动机是一个多模式匹配的数据结构。
    • 我们首先构造(trie)树并构建(fail)指针。
    • 这时候(trie)树就不再是(trie)树了,经过加了几个(fail)指针变成了一张有向图。
    • 如果存在这样一个无限的字符串,使得没有任何一个病毒是他的子串,那么会有什么情况呢?
    • 拿这个字符串到自动机上匹配,无论怎么样也到不了某个病毒串的结尾位置,因为构造的字符串无限长,所以他会在自动机里无限地转圈圈。
    • 所以问题转化为:
      • 在AC自动机上找一个环,这个环上没有节点是病毒串的结尾。
    • 注意一个节点的(fail)节点如果是结尾节点,那么他自身也应该是一个结尾节点。
    • 画个图看看
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 3e4 + 10;
    char s[maxn];
    int n;
    
    struct AC_Automaton
    {
        int trie[maxn][5];
        int val[maxn];
        int fail[maxn];
        int tot;
    
        void ins(char *str)
        {
            int len = strlen(str), p = 0;
            for(int k = 0; k < len; k++)
            {
                int ch = str[k] - '0';
                if(trie[p][ch] == 0) trie[p][ch] = ++tot;
                p = trie[p][ch];
            }
            val[p] = 1;
        }
    
        void build()
        {
            queue<int> q;
            for(int i = 0; i < 2; i++)
            {
                if(trie[0][i])
                {
                    //第二层指向根节点
                    fail[trie[0][i]] = 0;
                    q.push(trie[0][i]);
                }
            }
            while(q.size())
            {
                int x = q.front(); q.pop();
                for(int i = 0; i < 2; i++)
                {
                    if(trie[x][i])
                    {
                        fail[trie[x][i]] = trie[fail[x]][i];
                        val[trie[x][i]] |= val[fail[trie[x][i]]];
                        q.push(trie[x][i]);
                    }
                    else trie[x][i] = trie[fail[x]][i];
                }
            }
        }
    
        bool v1[maxn];
        
        void dfs(int x)
        {
            if(v1[x])
            {
                puts("TAK");
                exit(0);
            }
            if(val[x]) return;
            v1[x] = 1;
            if(trie[x][0]) dfs(trie[x][0]);
            if(trie[x][1]) dfs(trie[x][1]);
            v1[x] = 0;
        }
    }AC;
    
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", s);
            AC.ins(s);
        } AC.build();
        AC.dfs(0); //从字典树根节点开始找环
        puts("NIE"); //不存在无限的串
        return 0;
    }
    
  • 相关阅读:
    如何将一个类改造为线程安全
    50行代码实现缓存,JAVA内存模型原理
    Qt 解压/压缩文件
    QT学习笔记—1
    在http编程的门口飞牛网自动下单,查单
    QList 排序
    Qt 打开指定的文件
    spoj 375 query on a tree 题解
    uva 11388 GCD LCM题解
    uva 1476 Error Curves 题解
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12233485.html
Copyright © 2011-2022 走看看