POJ1699 Best Sequence(AC自动机+状压DP)
题目,求包含所有的给定的n个DNA片段的序列的最短长度。
AC自动机上的DP题。
- dp[S][u]表示已经包含的DNA片段集合为S,且当前后缀状态是自动机第u个结点的最短长度
- dp[0][0]=0
- 我为人人+队列轻松转移。。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 int tn,ch[222][4],fail[222],flag[222]; 8 int idx[128]; 9 void insert(char *s,int k){ 10 int x=0; 11 for(int i=0; s[i]; ++i){ 12 int y=idx[s[i]]; 13 if(ch[x][y]==0) ch[x][y]=++tn; 14 x=ch[x][y]; 15 } 16 flag[x]|=(1<<k); 17 } 18 void getfail(){ 19 memset(fail,0,sizeof(fail)); 20 queue<int> que; 21 for(int i=0; i<4; ++i){ 22 if(ch[0][i]) que.push(ch[0][i]); 23 } 24 while(!que.empty()){ 25 int x=que.front(); que.pop(); 26 for(int i=0; i<4; ++i){ 27 if(ch[x][i]){ 28 que.push(ch[x][i]); 29 fail[ch[x][i]]=ch[fail[x]][i]; 30 flag[ch[x][i]]|=flag[ch[fail[x]][i]]; 31 }else ch[x][i]=ch[fail[x]][i]; 32 } 33 } 34 } 35 struct Node{ 36 int s,x; 37 Node(int _s,int _x):s(_s),x(_x){} 38 }; 39 int d[1<<10][222],vis[1<<10][222]; 40 int main(){ 41 idx['A']=0; idx['C']=1; idx['G']=2; idx['T']=3; 42 int t,n; 43 char str[22]; 44 scanf("%d",&t); 45 while(t--){ 46 tn=0; 47 memset(ch,0,sizeof(ch)); 48 memset(flag,0,sizeof(flag)); 49 scanf("%d",&n); 50 for(int i=0; i<n; ++i){ 51 scanf("%s",str); 52 insert(str,i); 53 } 54 getfail(); 55 for(int i=0; i<(1<<n); ++i){ 56 for(int j=0; j<=tn; ++j) d[i][j]=INF; 57 } 58 d[0][0]=0; 59 memset(vis,0,sizeof(vis)); 60 vis[0][0]=1; 61 queue<Node> que; 62 que.push(Node(0,0)); 63 while(!que.empty()){ 64 int s=que.front().s,x=que.front().x; que.pop(); 65 for(int i=0; i<4; ++i){ 66 int ns=s|flag[ch[x][i]],nx=ch[x][i]; 67 if(d[ns][nx]>d[s][x]+1){ 68 d[ns][nx]=d[s][x]+1; 69 if(!vis[ns][nx]){ 70 vis[ns][nx]=1; 71 que.push(Node(ns,nx)); 72 } 73 } 74 } 75 vis[s][x]=0; 76 } 77 int res=INF; 78 for(int i=0; i<=tn; ++i){ 79 res=min(res,d[(1<<n)-1][i]); 80 } 81 printf("%d\n",res); 82 } 83 return 0; 84 }