zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    数据链路层
    补码加减法
    matlab函数
    HDU2159_二维完全背包问题
    HDU2844买表——多重背包初探
    HDU1025贫富平衡
    最大m段子段和
    01背包浮点数情况
    第K大01背包
    HDU2955 01背包
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7242285.html
Copyright © 2011-2022 走看看