题目一串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\n",++t,-1); 64 else printf("Case %d: %d\n",++t,res); 65 } 66 return 0; 67 }