【YBTOJ】【AC自动机】最短字符串

最短字符串

\(n\) 个由 \(\texttt{A,G,C,T}\) 组成的小字符串,构造一个大字符串 \(S\) ,使得每个小字符串是 \(S\) 的子串,最短的串 \(S\) 需要多长?

多组数据。

\(T\leq20,n\leq10,\text{字符串长度}\leq20\)

题解

想到了用状压记录某个字符串出没出现过,但是后面用着错误的状压 dp ……

正解:建立出 trie图 后,在trie 图上进行 bfs ,同时用状压记录某个字符串是否出现。一旦全部出现立即输出。

#include <bits/stdc++.h>
#define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
const int INF = 0x3f3f3f3f,N = 12,M = 22;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9'))ch=c,c=getchar();
	while(c>='0'&&c<='9')ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,k;
template <typename T> struct que{
	T a[N*M]; int st=1,ed=0;
	que(){st=1,ed=0;}
	inline void clear(){st=1,ed=0;}
	inline int size(){return ed-st+1;}
	inline bool empty(){return !(ed-st+1);}
	inline T front(){return a[st];}
	inline T back(){return a[ed];}
	inline void pop_front(){st++;}
	inline void pop_back(){ed--;}
	inline void push(T x){a[++ed] = x;}
	inline T operator [] (int x){return a[st+x-1];}
};
inline int getch(char ch){return ch == 'A' ? 1 : ch == 'G' ? 2 : ch == 'C' ? 3 : 4;}
int dp[(1<<10)+5][N*M];
struct ACauto{
	int c[N*M][5],fail[N*M],tot = 1;
	int sta[N*M];
	bool vis[N*M][(1<<10)+5];
	struct node{int p,s,w;};
	void init(){
		memset(c,0,sizeof(c));
		memset(fail,0,sizeof(fail));
		memset(sta,0,sizeof(sta));
		memset(vis,0,sizeof(vis));
		tot = 1;
	}
	void insert(char ch[],int id){
		int p = 1 , len = strlen(ch+1);
		for(int i = 1 ; i <= len ; i ++){
			int v = getch(ch[i]);
			if(!c[p][v]) c[p][v] = ++tot;
			p = c[p][v];
		}
		sta[p] |= 1<<(id-1);
	}
	void build(){
		for(int i = 1 ; i <= 4 ; i ++) c[0][i] = 1;
		que <int> q; q.push(1);
		while(!q.empty()){
			int p = q.front(); q.pop_front();
			sta[p] |= sta[fail[p]];
			for(int i = 1 ; i <= 4 ; i ++)
				if(c[p][i]) fail[c[p][i]] = c[fail[p]][i], q.push(c[p][i]);//, printf(" fail[%d] = %d\n",c[p][i],fail[c[p][i]]);
				else c[p][i] = c[fail[p]][i];
		}
	}
	void bfs(){
		queue <node> q;
		while(!q.empty()) q.pop();
		q.push((node){1,0,0});
		vis[1][0] = 1;
		while(!q.empty()){
			node u = q.front(); q.pop();
//			printf(" (%d,%d)\n",u.p,u.s);
			if(u.s == (1<<n)-1){printf("%d\n",u.w); return;}
			for(int i = 1 ; i <= 4 ; i ++){
				int p = c[u.p][i], s = u.s | sta[p];
				if(vis[p][s]) continue;
				vis[p][s] = 1;
				q.push((node){p,s,u.w+1});
			}
		}
	}
}ac;
char ch[M];
void work(){ 
	ac.init();
	n = read();
	for(int i = 1 ; i <= n ; i ++)
		scanf("%s",ch+1),
		ac.insert(ch,i);
	ac.build();
	ac.bfs();
}
signed main(){
	int T = read();
	while(T--) work();
	return 0;
}

posted @ 2021-09-24 22:40  Last-Order  阅读(88)  评论(0编辑  收藏  举报