Bzoj1195 [HNOI2006]最短母串 [AC自动机]

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)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<queue>
 6 using namespace std;
 7 const int mxn=605;
 8 int L1[mxn*(1<<12)],L2[mxn*(1<<12)];
 9 queue<int>q1,q2;
10 bool vis[mxn][(1<<12)];
11 int n;
12 int ans[mxn],num=0;
13 struct ACa{
14     int t[mxn][26];
15     int fail[mxn];
16     int end[mxn];
17     int S,cnt;
18     int q[670],hd,tl;
19     void init(){S=cnt=1;memset(end,0,sizeof end);return;}
20     void insert(char *s,int id){
21         int len=strlen(s),now=S;
22         for(int i=0;i<len;i++){
23             if(!t[now][s[i]-‘A‘])t[now][s[i]-‘A‘]=++cnt;
24             now=t[now][s[i]-‘A‘];
25         }
26         end[now]|=(1<<id);
27     }
28     void Build(){
29         hd=1;tl=0;
30         for(int i=0;i<26;i++)
31             if(t[S][i]){q[++tl]=t[S][i];fail[t[S][i]]=S;}
32             else t[S][i]=S;
33         while(hd<=tl){
34             int u=q[hd++];
35             int v,r;
36             for(int i=0;i<26;i++){
37                 if(t[u][i]){
38                     fail[t[u][i]]=t[fail[u]][i];
39                     end[t[u][i]]|=end[t[fail[u]][i]];
40                     q[++tl]=t[u][i];
41                 }
42                 else t[u][i]=t[fail[u]][i];
43             }
44         }
45         return;
46     }
47     void solve(){
48         hd=1;tl=1;int ed=(1<<n)-1;
49         q1.push(S),q2.push(0);
50         while(hd<=tl){
51             int u=q1.front();q1.pop();
52             int e=q2.front();q2.pop();
53 //            printf("  e:%d\n",e);
54             if(e==ed){//结束状态
55                 for(;hd>1;hd=L2[hd]){ans[++num]=L1[hd];}
56                 for(int i=num;i;i--)printf("%c",ans[i]+‘A‘);
57                 return;
58             }
59             for(int i=0;i<26;i++){
60                 if(!vis[t[u][i]][e|end[t[u][i]]]){
61                     L1[++tl]=i;
62                     L2[tl]=hd;
63                     q1.push(t[u][i]);
64                     q2.push(e|end[t[u][i]]);
65                     vis[t[u][i]][e|end[t[u][i]]]=1;
66                 }
67             }
68             hd++;
69         }
70     }
71 }ac;
72 char s[60];
73 int main(){
74     int i,j;
75     scanf("%d",&n);
76     ac.init();
77     for(i=0;i<n;i++)scanf("%s",s),ac.insert(s,i);
78 //    for(i=1;i<=ac.cnt;i++)if(ac.end[i])printf("%d %d\n",i,ac.end[i]);
79     ac.Build();
80     ac.solve();
81     return 0;
82 }
时间: 2025-01-02 11:20:59

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

BZOJ 1195: [HNOI2006]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1346  Solved: 450[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串

bzoj 1195: [HNOI2006]最短母串 爆搜

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 894  Solved: 288[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的

2782: [HNOI2006]最短母串

2782: [HNOI2006]最短母串 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3  Solved: 2[Submit][Status][Web Board] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度

[BZOJ1195]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MB Description 给定n个字符串(S1,S2,?,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,?,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果有多个字

【题解】最短母串

题目大意 ??有\(n\)个字符串\(s_1,s_2,\dots,s_n\),求一个最短的字符串\(S\),使这\(n\)个字符串都是\(S\)的子串. ? 题解 ??我们先对这\(n\)个字符串建AC自动机,这里我们对于Trie上的结点\(i\),定义一个状态\(state_i\),表示第\(i\)个结点对应的字符串,包含的题目中给出的哪些字符串. ??我们可以从Trie上的根节点,按照字典序BFS,我们用\(f\)表示当前经过的所有结点的包含的所有字符串,显然,当\(f\)包含所有字符串时,

BZOJ 4502: 串 AC自动机

4502: 串 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 195  Solved: 95[Submit][Status][Discuss] Description 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合S,然后它们定义一个字 符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合S中某个字符串的前缀. 比如对于字符串集合{"abc","bca"},字符串"abb&quo

最短母串

Ac_automaton的与状压的结合. 看题解说是Ac_automaton上的dp,但是实际上没有十分明显的转移过程,仅仅使用状压的方式记录某个串是否被选择过了(当然有建完Ac_automation然后跑纯状压dp的解法). 首先建立Ac_automaton(Trie图),额外维护一个sta数组,该数组为一个二进制表示数组,‘1’表示该串出现过,‘0’表示该串为出现过.这个信息需要在insert与generate(build)过程中统计,然而有趣的是,网上的大部分题解仅有由fail更新当前节点

AC自动机 &amp; fail树

[BZOJ 1195] 最短母串 题意 给定 n (n <= 12) 个子串 s (|s| <= 60) , 求一个最短母串. 分析 建 AC 自动机. 设 St 为每个点的状态, 在 fail 树上下传一下. 直接 BFS 找到第一个满的状态 (Node, State) . [BZOJ 4327] [JSOI 2012] 玄武密码 题意 给定一个母串和若干个模式串. 求每个模式串最多能在母串上匹配多少位. |S| <= 10000000, |T| <= 100, m <=

hdu5384 AC自动机模板题,统计模式串在给定串中出现的个数

http://acm.hdu.edu.cn/showproblem.php?pid=5384 Problem Description Danganronpa is a video game franchise created and developed by Spike Chunsoft, the series' name is compounded from the Japanese words for "bullet" (dangan) and "refutation&q