Time Limit: 10 Sec  Memory Limit: 32 MB
Submit: 1304  Solved: 439

Description

给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。

Input

第一行是一个正整数n(n<=12),表示给定的字符串的个数。以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

Output

只有一行,为找到的最短的字符串T。在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

Sample Input

2
ABCD
BCDABC

Sample Output

ABCDABC

HINT

 

Source

暴力+状压:http://www.cnblogs.com/SilverNebula/p/6445487.html

AC自动机+BFS

这其实是我看到这题时最先有的思路,然而看到数据范围明显是为了状压设的,就写状压了。之后发现确实有AC自动机的解法,那么果断学习一发。

(其实也需要状压)先建好AC自动机,标记好每个结点对应的包含串状态,然后从根节点开始BFS(BFS保证串最短),在每个状态从A到Z依次尝试扩展状态(保证字典序最小)

实际跑出来不比普通状压慢多少(大概是因为我的普通状压跑得太慢233)

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int mxn=;
int L1[mxn*(<<)],L2[mxn*(<<)];
queue<int>q1,q2;
bool vis[mxn][(<<)];
int n;
int ans[mxn],num=;
struct ACa{
int t[mxn][];
int fail[mxn];
int end[mxn];
int S,cnt;
int q[],hd,tl;
void init(){S=cnt=;memset(end,,sizeof end);return;}
void insert(char *s,int id){
int len=strlen(s),now=S;
for(int i=;i<len;i++){
if(!t[now][s[i]-'A'])t[now][s[i]-'A']=++cnt;
now=t[now][s[i]-'A'];
}
end[now]|=(<<id);
}
void Build(){
hd=;tl=;
for(int i=;i<;i++)
if(t[S][i]){q[++tl]=t[S][i];fail[t[S][i]]=S;}
else t[S][i]=S;
while(hd<=tl){
int u=q[hd++];
int v,r;
for(int i=;i<;i++){
if(t[u][i]){
fail[t[u][i]]=t[fail[u]][i];
end[t[u][i]]|=end[t[fail[u]][i]];
q[++tl]=t[u][i];
}
else t[u][i]=t[fail[u]][i];
}
}
return;
}
void solve(){
hd=;tl=;int ed=(<<n)-;
q1.push(S),q2.push();
while(hd<=tl){
int u=q1.front();q1.pop();
int e=q2.front();q2.pop();
// printf(" e:%d\n",e);
if(e==ed){//结束状态
for(;hd>;hd=L2[hd]){ans[++num]=L1[hd];}
for(int i=num;i;i--)printf("%c",ans[i]+'A');
return;
}
for(int i=;i<;i++){
if(!vis[t[u][i]][e|end[t[u][i]]]){
L1[++tl]=i;
L2[tl]=hd;
q1.push(t[u][i]);
q2.push(e|end[t[u][i]]);
vis[t[u][i]][e|end[t[u][i]]]=;
}
}
hd++;
}
}
}ac;
char s[];
int main(){
int i,j;
scanf("%d",&n);
ac.init();
for(i=;i<n;i++)scanf("%s",s),ac.insert(s,i);
// for(i=1;i<=ac.cnt;i++)if(ac.end[i])printf("%d %d\n",i,ac.end[i]);
ac.Build();
ac.solve();
return ;
}

Bzoj1195 [HNOI2006]最短母串 [AC自动机]的更多相关文章

  1. BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩

    题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入 第一行是一个正整数n(n<=12),表示给定的字符串的 ...

  2. BZOJ1195 [HNOI2006]最短母串 AC自动机 bfs

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 传送门 - BZOJ1195 题意概括 给出一堆串,然后求一个包含这些串的所有串的最短的中的字典序最小的. 题解 先造一个AC ...

  3. bzoj1195 [HNOI2006]最短母串 AC 自动机+状压+bfs

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1195 题解 建立 AC 自动机,然后构建出 trie 图. 然后直接在 trie 图上走.但是 ...

  4. 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html 题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串 ...

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

    Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12) ...

  6. BZOJ 1195: [HNOI2006]最短母串 AC自动机+状压+搜索

    思路比较直接. 由于 $n$ 很小,直接定义 $f[i][j]$ 表示当前在自动机中的节点 $i,$ 被覆盖串的集合为 $j$ 的方案数. #include <bits/stdc++.h> ...

  7. BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图

    BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2, ...

  8. [bzoj1195][HNOI2006]最短母串_动态规划_状压dp

    最短母串 bzoj-1195 HNOI-2006 题目大意:给一个包含n个字符串的字符集,求一个字典序最小的字符串使得字符集中所有的串都是该串的子串. 注释:$1\le n\le 12$,$1\le ...

  9. [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)

    题目传送门 题目描述 给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串. 输入格式 第一行是一个正整数n,表示给定的字符串的个数 ...

随机推荐

  1. LOJ#6342. 跳一跳(期望)

    题意 $n \leqslant 10^5$ Sol 随便推一推就好了吧.. $f[i] = \frac{f[i] + f[i +1] + \dots f[n]}{n - i + 1} + 1$ 移一下 ...

  2. SPOJ1043 GSS1(线段树)

    题意 给出$n$个数,每次询问区间$(l, r)$内最大字段和 Sol 在合并子树的时候,答案仅有四种情况 打四个标记维护即可 查询同理,用类似update的方式合并 注意查询的时候不能按照以前的方式 ...

  3. ElasticSearch High Level REST API【2】搜索查询

    如下为一段带有分页的简单搜索查询示例 在search搜索中大部分的搜索条件添加都可通过设置SearchSourceBuilder来实现,然后将SearchSourceBuilder RestHighL ...

  4. JDK和CGLIB动态代理原理区别

    JDK和CGLIB动态代理原理区别 https://blog.csdn.net/yhl_jxy/article/details/80635012 2018年06月09日 18:34:17 阅读数:65 ...

  5. MySQL - 在sql语句执行时是先执行触发器再检查约束条件的

    在sql语句执行时是先执行触发器再检查约束条件的

  6. Android_组件_Activity基础

    一.概述 Activity是应用组件,提供了用户交互的窗口.一个应用由多个彼此联系的Activity组成.它大多数情况是全屏窗口显示,也可以作为悬浮窗口 或者 多窗口模式. 二.生命周期 下图是来自A ...

  7. Python导入模块方法

    import module_name 导入整个模块 from module_name import function_name 导入特定函数 from module_name import funct ...

  8. 描述符应用 -- 让python变成一个强类型的语言

    众所周知,python是一门弱类型的语言,变量可以随意赋值成任意类型,但是通过描述符,我们可以把数据变成强类型的. 我们为数据设置数据描述符,因为数据描述的优先级大于实例属性,所以在给数据赋值的时候会 ...

  9. 使用JFreeChart生成报表

    1.JFreeChart简介    JFreeChart是JAVA平台上的一个开放的图表绘制类库.它完全使用JAVA语言编写,是为applications,servlets以及JSP等使用所设计.  ...

  10. 读书笔记jvm探秘之一:内存概况

    jvm内存大致可以分为六大块: 堆,虚拟机主要内存,可以形象的说,堆是对象的存储库,几乎所有的对象实例和数组都在此分配内存,当然也死于此,jvm垃圾回收机制(简称GC)主要处理的就是这个地方.它被所有 ...