[HNOI2006]最短母串 (AC自动机+状压)

拿这题练了练数组版的AC自动机

数据范围显然状压 插入时预处理出每个节点是哪个串的结束节点

然后建图 连fail指针的时候合并状态

为了最短显然需要按层转移,所以bfs

可以保证一达到末状态就return得到最优解

#include<queue>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,tot=0;
char s[55];
struct trie
{
    int son[28],st,fail;
}t[605];
void ins(char* str,int k)
{
    int l=strlen(str+1),root=0;
    for(int i=1;i<=l;i++)
    {
        int x=str[i]-'A';
        if(!t[root].son[x])t[root].son[x]=++tot;
        root=t[root].son[x];
    }
    t[root].st|=1<<(k-1);
}
void build()
{
    queue<int> q;
    for(int i=0;i<26;i++)
        if(t[0].son[i])q.push(t[0].son[i]);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<26;i++)
        {
            int &y=t[x].son[i];
            if(!y)
            {
                y=t[t[x].fail].son[i];
                continue;
            }
            t[y].fail=t[t[x].fail].son[i];
            t[y].st|=t[t[y].fail].st;
            q.push(y);
        }
    }
}
bool v[605][(1<<15)+5];
int let[(1<<22)+5],fa[(1<<22)+5],ans[605],num=0;
void bfs()
{
    queue<pair<int,int> > q;
    q.push(make_pair(0,0));
    int f=0,ss=0;
    while(!q.empty())
    {
        int x=q.front().first,nowst=q.front().second;
        q.pop();
        if(nowst==(1<<n)-1)
        {
            for(int i=f;i;i=fa[i])
                ans[++num]=let[i];
            for(int i=num;i;i--)putchar(ans[i]+'A');
            return ;
        }
        for(int i=0;i<26;i++)
        {
            int y=t[x].son[i],nxtst=nowst|t[y].st;
            if(!v[y][nxtst])
            {
                v[y][nxtst]=1;
                ss++;
                fa[ss]=f;
                let[ss]=i;
                q.push(make_pair(y,nxtst));
            }
        }
        f++;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        ins(s,i);
    }
    build();
    bfs();
    return 0;
}

 

上一篇:BZOJ 1192 [HNOI2006] 鬼谷子的钱袋 (整数拆分)


下一篇:python实现读取数据库的断点续传