题目描述
原题来自:HNOI 2006
给定 n个字符串 S1,S2,⋯,Sn 要求找到一个最短的字符串 T,使得这 n 个字符串都是 T 的子串。
输入格式
第一行是一个正整数 n,表示给定的字符串的个数;
以下的 n 行,每行有一个全由大写字母组成的字符串。
输出格式
只有一行,为找到的最短的字符串 T。
在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
样例
样例输入
2
ABCD
BCDABC
样例输出
ABCDABC
数据范围与提示
对于全部数据,1≤n≤12,1≤∣Si∣≤50。
题意:(挂loj是因为我的解法在bzoj上T了并且我不想调QAQ)
给你$n$个字符串,求他们的最短母串,即求一个最短字符串使得这$n$个字符串都是它的子串。若长度相同输出字典序最小的。
题解:
建出$AC$自动机后问题转化成找一条最短的路径覆盖所有$end$节点。
那么我们可以考虑对每个节点维护一个压缩状态表示从根走到该点包含了哪些字符串。
然后从根开始沿$bfs$序遍历(保证字典序最小)并记录路径,若合法则输出答案。
这题主要是教会了我一个真理:
当你发现某个代码已经改不出来的时候,重构代码总是会给你惊喜……
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define MAXN 15 #define MAXM 605 #define ll long long struct node{ int son[30],s; }tree[MAXM]; struct way{ int las; char ch; }p[MAXM*(1<<MAXN)]; int tot=1,nxt[MAXM]; bool vis[MAXM][1<<MAXN]; char str[MAXN],ans[MAXN]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void add(int p,char *str){ int N=strlen(str),u=1; for(int i=0;i<N;i++){ int ch=str[i]-'A'; if(!tree[u].son[ch]) tree[u].son[ch]=++tot; u=tree[u].son[ch]; } tree[u].s|=(1<<p); return; } inline void get_nxt(){ for(int i=0;i<26;i++) tree[0].son[i]=1; queue<int> q; q.push(1); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<26;i++){ if(tree[u].son[i]){ q.push(tree[u].son[i]); nxt[tree[u].son[i]]=tree[nxt[u]].son[i]; tree[tree[u].son[i]].s|=tree[tree[nxt[u]].son[i]].s; } else tree[u].son[i]=tree[nxt[u]].son[i]; } } return; } inline void solve(int N){ int end=(1<<N)-1; queue<int> q1,q2; q1.push(1); q2.push(0); int hd=1,tl=1; while(!q1.empty() && !q2.empty()){ int u=q1.front();q1.pop(); int sta=q2.front();q2.pop(); if(sta==end){ int cnt=0; for(;hd>1;hd=p[hd].las) ans[++cnt]=p[hd].ch; for(int i=cnt;i>=1;i--) printf("%c",ans[i]); printf(" "); return; } for(int i=0;i<26;i++){ if(!vis[tree[u].son[i]][(tree[tree[u].son[i]].s)|(sta)]){ vis[tree[u].son[i]][(tree[tree[u].son[i]].s)|(sta)]=1; q1.push(tree[u].son[i]); q2.push((tree[tree[u].son[i]].s)|(sta)); p[++tl].las=hd,p[tl].ch=i+'A'; } } hd++; } return; } int main(){ int N=read(); for(int i=0;i<N;i++) scanf("%s",str),add(i,str); get_nxt(); solve(N); return 0; }