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

 

posted @ 2017-12-15 07:50  19992147  阅读(214)  评论(0编辑  收藏  举报