• bzoj1195


    AC自动机+状压dp

    多串匹配要想ac自动机

    dp[i][S]表示在i状态选中S

    转移就用bfs,每个点通过fail收集信息,不要忘记通过fail传递

    昨天搞不明白为什么自动机每次只可以转移儿子,不可以转移fail,问了问大概知道因为儿子是最长的后缀,包含的信息最多,包含了其他fail的信息,就相当于收集了其他fail的东西,就不用走了,但是一定要收集,这跟kmp很像,kmp就是走最大的后缀,这里也是,这样就可以保证不遗补漏同时加速

    字典序最大在bfs时已经保证了,感觉比较显然,每次先拓展字典序最小的字符,bfs又求最短路,正好保证了字典序最小

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 605;
    int n;
    char s[N];
    namespace ac_automation 
    {
        int cnt, root, tot;
        int id[N];
        struct DP {
            short d, c; 
            short pre[2];
            DP () { d = -1; }
        } dp[N][1 << 12];
        struct node {
            int fail;
            int ch[26];
        } t[N];
        void ins(char *s)
        {
            int len = strlen(s), now = root;
            for(int i = 0; i < len; ++i) 
            {
                int c = s[i] - 'A';
                if(!t[now].ch[c]) t[now].ch[c] = ++tot;
                now = t[now].ch[c];
            }
            id[now] |= 1 << (cnt++);
        }
        void construct_fail() 
        {
            queue<int> q;
            for(int i = 0; i < 26; ++i) if(t[root].ch[i]) q.push(t[root].ch[i]);
            while(!q.empty())
            {
                int u = q.front();
                q.pop();
                for(int i = 0; i < 26; ++i) 
                {
                    int &v = t[u].ch[i];
                    if(!v) v = t[t[u].fail].ch[i];
                    else
                    {
                        t[v].fail = t[t[u].fail].ch[i];
                        id[v] |= id[t[v].fail];
                        q.push(v);
                    }
                }
            }
        }
        void print(int u, int S) 
        {
            if(u == root && S == 0) return;
            print(dp[u][S].pre[0], dp[u][S].pre[1]);
            printf("%c", (char)(dp[u][S].c + 'A'));
        }
        void solve()
        {
            int a = 0, b = 0, mn = 0x3f3f3f3f;
            queue<int> q;
            q.push(0);
            q.push(0);
            dp[0][0].d = 0;
            while(!q.empty())
            {
                int u = q.front(); q.pop();
                int S = q.front(); q.pop();
                if(S == (1 << n) - 1) 
                {
                    if(dp[u][S].d < mn) 
                    {
                        a = u;
                        b = S;
                        mn = dp[u][S].d; 
                    }
                    continue;
                }
                for(int i = 0; i < 26; ++i) if(t[u].ch[i])
                {
                    int v = t[u].ch[i];
                    dp[v][S | id[v]].c = i;
                    if(dp[v][S | id[v]].d == -1) 
                    {
                        dp[v][S | id[v]].d = dp[u][S].d + 1;
                        dp[v][S | id[v]].pre[0] = u;
                        dp[v][S | id[v]].pre[1] = S; 
                        q.push(v);
                        q.push(S | id[v]);
                    }
                }
            }     
            print(a, b);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
        }
    }
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%s", s);
            ac_automation :: ins(s);
        }
        ac_automation :: construct_fail();
        ac_automation :: solve();
        return 0;
    }
    View Code
  • 相关阅读:
    怎么快速掌握一门新技术
    Linq相关
    C# 参数按照ASCII码从小到大排序(字典序)
    测试工具
    sql 创建临时表
    sql行合并
    WCF相关
    免费开源分布式系统日志收集框架 Exceptionless
    VPS,虚拟主机,云主机,独立服务器区别
    c# Dictionary的遍历和排序
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8041134.html
Copyright © 2020-2023  润新知