HDU 2457 DNA repair (AC自动机+DP)

时间:2021-12-20 19:27:58

题意:给N个串,一个大串,要求在最小的改变代价下,得到一个不含上述n个串的大串。

思路:dp,f[i][j]代表大串中第i位,AC自动机上第j位的最小代价。

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<queue>
 7 std::queue<int>Q;
 8 int ch[10005][5],end[10005],f[1005][1005],sz,root,fail[100005],n,Tcase;
 9 char s[10005];
10 int newnode(){
11     for (int i=0;i<=3;i++) 
12      ch[sz][i]=-1;
13     end[sz]=0;
14     sz++; 
15     return sz-1;
16 }
17 void clear(){
18     sz=0;root=newnode();
19 }
20 int num(char c){
21     if (c=='A') return 0;
22     else
23     if (c=='T') return 1;
24     else
25     if (c=='G') return 2;
26     else
27     if (c=='C') return 3;
28     return 0;
29 }
30 void insert(){
31     scanf("%s",s);
32     int len=strlen(s);
33     int now=root;
34     for (int i=0;i<len;i++){
35         if (ch[now][num(s[i])]==-1) ch[now][num(s[i])]=newnode();
36         now=ch[now][num(s[i])];
37     }
38     end[now]=1;
39 }
40 void build(){
41     int now=root;
42     std::queue<int>Q;
43     fail[root]=root;
44     for (int i=0;i<=3;i++) 
45      if (ch[root][i]==-1) ch[root][i]=root;
46      else fail[ch[root][i]]=root,Q.push(ch[root][i]);
47     while (!Q.empty()){
48         int now=Q.front();Q.pop();
49         if (end[fail[now]]==1) end[now]|=1;
50         for (int i=0;i<=3;i++){
51             if (ch[now][i]==-1) ch[now][i]=ch[fail[now]][i];
52             else fail[ch[now][i]]=ch[fail[now]][i],Q.push(ch[now][i]);
53         }
54     } 
55 }
56 void dp(){
57     scanf("%s",s);
58     int len=strlen(s);
59     for (int i=0;i<=len;i++)
60      for (int j=0;j<=sz;j++)
61       f[i][j]=99999999;
62     f[0][root]=0;
63     for (int i=0;i<len;i++)
64      for (int j=0;j<sz;j++)
65       if (f[i][j]<99999999){
66             for (int k=0;k<=3;k++){
67                 int now=ch[j][k];
68                 if (end[now]) continue;
69                 int tmp;
70                 if (k==num(s[i])) tmp=f[i][j];
71                 else tmp=f[i][j]+1;
72                 f[i+1][now]=std::min(f[i+1][now],tmp);
73             }
74       }  
75     int ans=99999999;
76     for (int i=0;i<sz;i++)
77      ans=std::min(ans,f[len][i]);
78     if (ans==99999999) ans=-1;
79     printf("%d\n",ans);   
80 }
81 int main(){
82     while (scanf("%d",&n)!=EOF){
83         if (n==0) return 0;
84         Tcase++;
85         printf("Case %d: ",Tcase);
86         clear();
87         for (int i=1;i<=n;i++)
88          insert();
89         build();
90         dp();
91     }
92 }