BZOJ1195 [HNOI2006]最短母串 AC自动机 bfs
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
传送门 - BZOJ1195
题意概括
给出一堆串,然后求一个包含这些串的所有串的最短的中的字典序最小的。
题解
先造一个AC自动机,多模匹配嘛。
然后bfs在AC自动机上面走,两维状态,dis[i][j]表示已经走到过的串状态为i,在AC自动机上面的位置为j的最短距离。
然后这题居然要卡空间!
坑死了。
然后用了short
wa掉了。
发现short实在小的可怜,然后把几个大的数组的有必要的一个开了int,然后30MB卡着限制过去了~
开心!!
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; struct Trie{ int e,fail,next[26]; void init(){ e=fail=0; memset(next,0,sizeof next); } }tree[605]; int cnt; void AC_Prepare(){ cnt=1; tree[0].init(),tree[1].init(); for (int i=0;i<26;i++) tree[0].next[i]=1; } void add(char ch[],int bh){ int len=strlen(ch),rt=1,t; for (int i=0;i<len;i++){ t=ch[i]-'A'; if (!tree[rt].next[t]){ tree[++cnt].init(); tree[rt].next[t]=cnt; } rt=tree[rt].next[t]; } tree[rt].e|=1<<bh; } void build_AC(){ int q[605],head=0,tail=0,rt,son,k; tree[0].fail=1,q[++tail]=1; while (head<tail){ rt=q[++head]; for (int i=0;i<26;i++){ son=tree[rt].next[i]; if (!son){ tree[rt].next[i]=tree[tree[rt].fail].next[i]; continue; } k=tree[rt].fail; while (!tree[k].next[i]) k=tree[k].fail; tree[son].fail=tree[k].next[i]; tree[son].e|=tree[tree[k].next[i]].e; q[++tail]=son; } } } int n,head,tail,pre[1<<12][605]; short dis[1<<12][605]; bool f[1<<12][605]; char str[55],chosen[1<<12][605],ansstr[605]; struct Queue{ short x,y; void push(int a,int b){ x=a,y=b; } void pushout(int &a,int &b){ a=x,b=y; } }q[2500000]; int main(){ scanf("%d",&n); AC_Prepare(); for (int i=0;i<n;i++){ scanf("%s",str); add(str,i); } build_AC(); memset(f,0,sizeof f); memset(dis,0,sizeof dis); memset(q,0,sizeof q); head=tail=0; q[++tail].push(0,1); dis[0][1]=0,f[0][1]=1,pre[0][1]=0; int ans=-1,x,y,x_,y_; while (head<tail){ q[++head].pushout(x,y); for (int i=0;i<26;i++){ y_=tree[y].next[i]; x_=x|tree[y_].e; if (f[x_][y_]) continue; dis[x_][y_]=dis[x][y]+1; chosen[x_][y_]=i; pre[x_][y_]=head; f[x_][y_]=1; q[++tail].push(x_,y_); if (x_==(1<<n)-1){ ans=tail; break; } } if (ans!=-1) break; } q[ans].pushout(x,y); int ansdis=dis[x][y],xnow,ynow; for (int j=ansdis,i=ans;j>=1&&i;j--,i=pre[xnow][ynow]){ q[i].pushout(xnow,ynow); ansstr[j]=chosen[xnow][ynow]+'A'; } for (int i=1;i<=ansdis;i++) printf("%c",ansstr[i]); return 0; }