题意:给定n个疾病DNA序列,和一个待修复序列str。用最小的次数修改待修复序列,使其不含疾病DNA序列。
思路:AC自动机+DP
建自动机 并加上虚拟节点 每一个节点作为一个dp第二维状态
dp[i][j] 表示修复str前i个字符,且当前状态为j的最小修改次数
str从1开始 AC自动 树根标号为0 dp[0][0]=0;
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+(j代表的当前字符!=str[i+1]))
ans=min(ans,dp[m-1][j]); (0<=j<top) top是自动机节点数
1 #include<iostream>
2 using namespace std;
3 #define MAXN 1002
4 int dp[MAXN][MAXN];
5 struct node
6 {
7 int id,name;
8 bool end;
9 node *next[4],*father,*failink;
10 };
11 int n,m,top=0;
12 node *head;
13 node memo[MAXN];
14 node *Q[MAXN];
15 char str[MAXN];
16 int get(char c)
17 {
18 switch(c)
19 {
20 case 'A': return 0;
21 case 'G': return 1;
22 case 'C': return 2;
23 case 'T': return 3;
24 }
25 }
26 void insert(node *t,char c[],int i)
27 {
28 if(i==strlen(c))
29 {
30 t->end=1; return ;
31 }
32 int x=get(c[i]);
33 if(t->next[x]==NULL)
34 {
35 //cout<<i<<" "<<top<<" "<<x<<endl;
36 node *p=&memo[top]; p->id=top++; p->father=t; p->name=x;
37 t->next[x]=p;
38 }
39 insert(t->next[x],c,i+1);
40 }
41 void set_fail_link()
42 {
43 int i,j;
44 int front,behind;
45 Q[front=behind=0]=head;
46 node *p,*t;
47 while(front<=behind)
48 {
49 p=Q[front++];
50 if(p->father==head) p->failink=head;
51 else if(p!=head)
52 {
53 t=p->father->failink;
54 int x=p->name;
55 //cout<<x<<endl;
56 while(1)
57 {
58 if(t->next[x]!=NULL)
59 {
60 if(t->next[x]->end) p->end=1;
61 p->failink=t->next[x];
62 break;
63 }
64 else if(t==head)
65 {
66 p->failink=t; break;
67 }
68 else t=t->failink;
69 }
70 }
71 for(i=0;i<4;i++)
72 {
73 if(p->next[i]!=NULL) Q[++behind]=p->next[i];
74 else //建立虚拟节点
75 {
76 if(p==head) p->next[i]=p;
77 else p->next[i]=p->failink->next[i];
78 }
79 }
80 }
81 }
82 int dynamic_programming()
83 {
84
85 int m=strlen(str);
86
87 memset(dp,0x3f,sizeof(dp));
88 int i,j,k;
89 node *p,*q;
90 dp[0][0]=0;
91 for(i=0;i<m-1;i++)
92 for(j=0;j<top;j++)
93 if(dp[i][j]<MAXN)
94 for(k=0;k<4;k++)
95 {
96 p=&memo[j];
97 q=p->next[k];
98 if(q->end==0)
99 dp[i+1][q->id]=min(dp[i+1][q->id],dp[i][j]+(k!=get(str[i+1])));
100 }
101 int ans=MAXN+1;
102 for(j=0;j<top;j++) ans=min(ans,dp[m-1][j]);
103 if(ans>MAXN) return -1;
104 return ans;
105 }
106 int main()
107 {
108 char c[21];
109 int i,j=0;
110 scanf("%d",&n);
111 str[0]='1';
112 while(n!=0)
113 {
114 j++;
115 top=0;
116 memset(memo,0,sizeof(memo));
117 head=&memo[top]; head->id=top++;
118 for(i=1;i<=n;i++)
119 {
120 scanf("%s",c);
121 insert(head,c,0);
122 }
123 scanf("%s",str+1);
124 set_fail_link();
125 printf("Case %d: %d\n",j,dynamic_programming());
126 scanf("%d",&n);
127 }
128 return 0;
129 }