zoukankan      html  css  js  c++  java
  • P2322 [HNOI2006]最短母串问题

    传送门

    看到题面肯定先搞个AC自动机

    考虑一位一位填字符

    那么在自动机上就是一位一位匹配

    考虑什么时候包含了所有子串

    显然是经过了所有的结束标记(当然fail上的也算经过)

    最多只有11个单词

    考虑状态压缩

    经过第 i 个单词结尾就把状态的第 i 位  | 1

    然后就可以广搜找了

    因为扩展是从 A 到 Z

    所以一旦找到了就是字典序最小的答案

    但是存答案也有点麻烦,具体还是看代码吧

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1e5+7;
    const int M=2e6+7;
    int n;
    int c[N][27],pd[N],fail[N],cnt;
    char a[N];
    inline void ins(int k)
    {
        int u=0,len=strlen(a);
        for(int i=0;i<len;i++)
        {
            int v=a[i]-'A'+1;
            if(!c[u][v]) c[u][v]=++cnt;
            u=c[u][v];
        }
        pd[u]|=(1<<k);//注意是 '|=' 可能有重复的单词
    }
    queue <int> qa;
    void pre()
    {
        for(int i=1;i<=26;i++) if(c[0][i]) qa.push(c[0][i]);
        while(!qa.empty())
        {
            int u=qa.front(); qa.pop();
            for(int i=1;i<=26;i++)
            {
                int &v=c[u][i];
                if(!v) c[u][i]=c[fail[u]][i];
                else
                {
                    fail[v]=c[fail[u]][i];
                    pd[v]= (pd[v]|pd[fail[v]]);//把fail上的状态也转过来
                    qa.push(v);
                }
            }
        }
    }
    
    struct node{
        int pos,v,id;//pos是AC机上的位置,v是当前状态,id是编号
    };//搜索的状态
    queue <node> qb;
    bool f[1007][1<<12];//记忆化数组,是否到过AC机上第i个点时状态为j
    int from[M],b[M],tot;//存答案,from存编号为i时上一个位置的编号,b存当前编号时的字符
    void print(int &x)//递归输出答案
    {
        if(!x) return;
        print(from[x]);
        printf("%c",b[x]+'A'-1);
    }
    void bfs()
    {
        qb.push((node){0,0,0});
        while(!qb.empty())
        {
            node x=qb.front(); qb.pop();
            if(x.v==((1<<n)-1))//如果找到答案
            {
                print(x.id);//输出
                return;
            }
            for(int i=1;i<=26;i++)
            {
                int &pos=c[x.pos][i],v=x.v|pd[pos];
                if(f[pos][v]) continue;//记忆化
                f[pos][v]=1;
                from[++tot]=x.id; b[tot]=i;
                qb.push((node){pos,v,tot});
            }
        }
    }
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",a);
            ins(i-1);
        }
        pre();
        bfs();
        return 0;
    }
  • 相关阅读:
    C#中添加文本框的上标及文字大小
    综采工作面设备接替计划管理系统
    一位年轻女董事长的27条忠告
    开发人员一定要加入收藏夹的网站
    哈佛图书馆墙上的名训
    加密、解密.NET字符串
    C#文件上传下载
    DotNetNuke3.0.8 简体中文语言包(可直接导入版)发布
    DNN的Core Team
    DotNetNuke3.0.8文件管理器的错误及解决方法
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9689534.html
Copyright © 2011-2022 走看看