bzoj2938

Posted 123456

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2938相关的知识,希望对你有一定的参考价值。

AC自动机+trie图优化

很明显就是要一个串不能匹配到任何一个病毒,那么我们就建一个AC自动机

不能匹配的话也就是一个节点不能是单词结束节点,fail指针也不能是结束节点

然后就卡壳了。。。zz

我们把自动机建成trie图,也就是不存在的节点直接指向原来fail指针,然后我们只要在这个图上找有没有环就可以了。

因为ac自动机当不能继续匹配,也就是没有儿子节点,就会沿着fail指针走,否则就沿着儿子走,于是我们就把不存在的儿子指向fail,是一种优化,如果有一个无限长的串,也就是这个串能不停地匹配,不会走到危险节点,那么肯定就有环了,因为自动机是有限的。

技术分享
#include<bits/stdc++.h>
using namespace std;
const int N = 30010;
int n;
char s[N];
struct acautomation {
    int root, cnt;  
    int child[N][2], fail[N], danger[N], vis[N], inq[N];
    void insert(char s[])
    {
        int now = root;
        for(int i = 0; i < strlen(s); ++i)
        {
            int x = s[i] - 0;
            if(!child[now][x]) child[now][x] = ++cnt;
            now = child[now][x];
        }
        danger[now] = 1;
    }
    void build_fail()
    {
        queue<int> q;
        for(int i = 0; i < 2; ++i) if(child[root][i])
        {
            q.push(child[root][i]);
            fail[child[root][i]] = 0;
        }
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int i = 0; i < 2; ++i) 
            {
                int v = child[u][i];
                if(!v) child[u][i] = child[fail[u]][i];
                else
                {
                    int now = fail[u];
                    while(now != root && !child[now][i]) now = fail[now];
                    fail[v] = child[now][i];
                    danger[v] |= danger[fail[v]];
                    q.push(v);
                }
            }
        }
    }
    bool dfs(int u)
    {
        inq[u] = 1;
        for(int i = 0; i < 2; ++i)
        {
            int v = child[u][i];
            if(inq[v]) return true;
            if(danger[v] || vis[v]) continue;
            vis[v] = 1;
            if(dfs(v)) return true; 
        }
        inq[u] = 0;
        return false;
    }
} ac;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%s", s);
        ac.insert(s);
    }
    ac.build_fail();
    if(ac.dfs(0)) puts("TAK");
    else puts("NIE");
    return 0;
}
View Code

 

以上是关于bzoj2938的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2938 [Poi2000]病毒 AC自动机

BZOJ2938: [Poi2000]病毒

[bzoj 2938] [Poi2000]病毒]

bzoj2938 病毒

bzoj2938

bzoj 2938 AC自动机