【poj3691-DNA repair】AC自动机+DP
题意:给n个病毒DNA序列,再给一个DNA序列,问该序列至少修改多少个碱基能不含任何病毒DNA。病毒DNA序列一共不超过1000,询问的DNA长度不超过1000。
题解:DP:d[l][p]表示询问到第l位、当前在AC自动机上的位置为p时的最少修改数,用d[l][p]推d[l+1][x]。本来打的是递归,结果递归死循环了。。于是改成递推了。
不想清楚的话递归真的好容易死掉TAT
1 //poj3691
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<iostream>
6 #include<queue>
7 using namespace std;
8
9 const int N=1100,INF=(int)1e9;
10 int n,num,sl,ans,d[N][N];
11 char s[N];
12 struct node{
13 int fail,fa,bk,son[5];
14 }a[N];
15 queue<int> q;
16
17 int minn(int x,int y){return x<y ? x:y;}
18
19 int idx(char c)
20 {
21 if(c=='A') return 1;
22 if(c=='T') return 2;
23 if(c=='C') return 3;
24 if(c=='G') return 4;
25 }
26
27 void clear(int x)
28 {
29 a[x].bk=a[x].fail=a[x].fa=0;
30 memset(a[x].son,0,sizeof(a[x].son));
31 }
32
33 void read_trie()
34 {
35 scanf("%s",s);
36 int x=0,l=strlen(s);
37 for(int i=0;i<l;i++)
38 {
39 int ind=idx(s[i]);
40 if(!a[x].son[ind])
41 {
42 clear(++num);
43 a[x].son[ind]=num;
44 a[num].fa=x;
45 }
46 x=a[x].son[ind];
47 }
48 a[x].bk=1;
49 }
50
51 void buildAC()
52 {
53 while(!q.empty()) q.pop();
54 for(int i=1;i<=4;i++)
55 if(a[0].son[i]) q.push(a[0].son[i]);
56 while(!q.empty())
57 {
58 int x=q.front();q.pop();
59 int fail=a[x].fail;
60 for(int i=1;i<=4;i++)
61 {
62 if(a[x].son[i])
63 {
64 int y=a[x].son[i],z=a[fail].son[i];
65 a[y].fail=z;
66 a[y].bk|=a[z].bk;
67 q.push(y);
68 }
69 else a[x].son[i]=a[fail].son[i];
70 }
71 }
72 }
73
74 int main()
75 {
76 freopen("a.in","r",stdin);
77 freopen("a.out","w",stdout);
78 int T=0;
79 while(1)
80 {
81 scanf("%d",&n);
82 if(!n) return 0;
83 num=0;
84 clear(0);
85 for(int i=1;i<=n;i++) read_trie();
86 buildAC();
87 scanf("%s",s+1);
88 sl=strlen(s+1);
89 ans=INF;
90 memset(d,63,sizeof(d));
91 d[0][0]=0;
92 for(int i=0;i<sl;i++)
93 {
94 for(int j=0;j<=num;j++)//在AC自动机上的位置
95 {
96 if(d[i][j]<INF)
97 {
98 int ind=idx(s[i+1]);
99 int x=a[j].son[ind];
100 for(int k=1;k<=4;k++)
101 {
102 int y=a[j].son[k];
103 if(a[y].bk || x==y) continue;
104 d[i+1][y]=minn(d[i+1][y],d[i][j]+1);
105 }
106 if(a[x].bk==0)
107 d[i+1][x]=minn(d[i+1][x],d[i][j]);
108 }
109 }
110 }
111 for(int i=0;i<=num;i++) ans=minn(ans,d[sl][i]);
112 if(ans<INF) printf("Case %d: %d\n",++T,ans);
113 else printf("Case %d: -1\n",++T);
114 }
115 return 0;
116 }