[BZOJ1195] [HNOI2006] 最短母串(AC自动机+状压bfs)
[BZOJ1195] [HNOI2006] 最短母串(AC自动机+状压bfs)
题面
给定n个字符串(S1,S2...Sn),要求找到一个最短的字符串T,使得这n个字符串都包含这个字符串
\(n \leq 12,|S| \leq 50\)
分析
在自动机上bfs,bfs的深度就是字符串长度。\(n\)很小,因此把匹配情况压成一个二进制数即可。注意还要记录前驱,方便输出方案。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<bitset>
#define maxn 600
#define maxb (1<<12)
#define maxc 26
using namespace std;
struct AC_automaton{
int ch[maxn+5][maxc];
int fail[maxn+5];
int cnt_end[maxn+5];
int id[maxn+5];
int ptr;
void insert(char *s,int num){
int n=strlen(s+1);
int x=0;
for(int i=1;i<=n;i++){
int c=s[i]-'A';
if(!ch[x][c]) ch[x][c]=++ptr;
x=ch[x][c];
}
cnt_end[x]|=(1<<(num-1));
}
void get_fail(){
queue<int>q;
for(int i=0;i<maxc;i++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<maxc;i++){
if(ch[x][i]){
fail[ch[x][i]]=ch[fail[x]][i];
cnt_end[ch[x][i]]|=cnt_end[ch[fail[x]][i]];
q.push(ch[x][i]);
}else{
ch[x][i]=ch[fail[x]][i];
}
}
}
}
inline int size(){
return ptr;
}
}T;
int n;
char s[maxn+5];
int vis[maxn+5][maxb+5];
struct node{
int x;
int sta;
int last;
int cr;
node(){
}
node(int _x,int _sta,int _last,int _cr){
x=_x;
sta=_sta;
last=_last;
cr=_cr;
}
}q[maxn*maxb+5];
void bfs(){
static char ans[maxn+5];
int head=1,tail=0;
q[++tail]=node(node(0,0,0,0));
while(head<=tail){
// printf("(%d,%d,%d,%d)\n",q[head].x,q[head].sta,q[head].last,q[head].cr);
if(q[head].sta==(1<<n)-1){
int sz=0;
for(int i=head;i>0;i=q[i].last){
ans[++sz]=q[i].cr+'A';
}
for(int i=sz-1;i>=1;i--) putchar(ans[i]);
return;
}
for(int i=0;i<4;i++){
int nex=T.ch[q[head].x][i];
int ss=q[head].sta|T.cnt_end[nex];
if(!vis[nex][ss]){
q[++tail]=node(nex,ss,head,i);
vis[nex][ss]=1;
}
}
head++;
}
}
int main(){
int sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
T.insert(s,i);
sum+=strlen(s+1);
}
T.get_fail();
bfs();
}
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢