HDU2457 DNA repair(AC自动机+DP)

题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段。

这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来。

dp[i][j]表示原DNA前i位(在AC自动机上转移i步)且后缀状态为AC自动机结点j的最少需要修改的基因数

转移我为人人型,从dp[i][j]向ATCG四个方向转移到dp[i+1][j'],如果结点被标记包含致病基因就不能转移。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 #define INF (1<<30)
 6 int tn,ch[1111][4],fail[1111],idx[128];
 7 bool flag[1111];
 8 void insert(char *s){
 9     int x=0;
10     for(int i=0; s[i]; ++i){
11         int y=idx[s[i]];
12         if(ch[x][y]==0) ch[x][y]=++tn;
13         x=ch[x][y];
14     }
15     flag[x]=1;
16 }
17 void init(){
18     memset(fail,0,sizeof(fail));
19     queue<int> que;
20     for(int i=0; i<4; ++i){
21         if(ch[0][i]) que.push(ch[0][i]);
22     }
23     while(!que.empty()){
24         int x=que.front(); que.pop();
25         for(int i=0; i<4; ++i){
26             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i],flag[ch[x][i]]|=flag[ch[fail[x]][i]];
27             else ch[x][i]=ch[fail[x]][i];
28         }
29     }
30 }
31 int d[1111][1111];
32 int main(){
33     idx['A']=0; idx['G']=1; idx['C']=2; idx['T']=3;
34     char str[1111];
35     int n,t=0;
36     while(~scanf("%d",&n) && n){
37         tn=0;
38         memset(ch,0,sizeof(ch));
39         memset(flag,0,sizeof(flag));
40         while(n--){
41             scanf("%s",str);
42             insert(str);
43         }
44         init();
45         scanf("%s",str+1);
46         n=strlen(str+1);
47         for(int i=0; i<=n; ++i){
48             for(int j=0; j<=tn; ++j) d[i][j]=INF;
49         }
50         d[0][0]=0;
51         for(int i=0; i<n; ++i){
52             for(int j=0; j<=tn; ++j){
53                 if(d[i][j]==INF || flag[j]) continue;
54                 for(int k=0; k<4; ++k){
55                     if(flag[ch[j][k]]) continue;
56                     if(idx[str[i+1]]==k) d[i+1][ch[j][k]]=min(d[i+1][ch[j][k]],d[i][j]);
57                     else d[i+1][ch[j][k]]=min(d[i+1][ch[j][k]],d[i][j]+1);
58                 }
59             }
60         }
61         int res=INF;
62         for(int i=0; i<=tn; ++i) res=min(res,d[n][i]);
63         if(res==INF) printf("Case %d: %d
",++t,-1);
64         else printf("Case %d: %d
",++t,res);
65     }
66     return 0;
67 }
原文地址:https://www.cnblogs.com/WABoss/p/5170026.html