题目一串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]; 27 else ch[x][i]=ch[fail[x]][i]; 28 flag[ch[x][i]]|=flag[ch[fail[x]][i]]; 29 } 30 } 31 } 32 int d[1111][1111]; 33 int main(){ 34 idx[‘A‘]=0; idx[‘G‘]=1; idx[‘C‘]=2; idx[‘T‘]=3; 35 char str[1111]; 36 int n,t=0; 37 while(~scanf("%d",&n) && n){ 38 tn=0; 39 memset(ch,0,sizeof(ch)); 40 memset(flag,0,sizeof(flag)); 41 while(n--){ 42 scanf("%s",str); 43 insert(str); 44 } 45 init(); 46 scanf("%s",str+1); 47 n=strlen(str+1); 48 for(int i=0; i<=n; ++i){ 49 for(int j=0; j<=tn; ++j) d[i][j]=INF; 50 } 51 d[0][0]=0; 52 for(int i=0; i<n; ++i){ 53 for(int j=0; j<=tn; ++j){ 54 if(d[i][j]==INF || flag[j]) continue; 55 for(int k=0; k<4; ++k){ 56 if(flag[ch[j][k]]) continue; 57 if(idx[str[i+1]]==k) d[i+1][ch[j][k]]=min(d[i+1][ch[j][k]],d[i][j]); 58 else d[i+1][ch[j][k]]=min(d[i+1][ch[j][k]],d[i][j]+1); 59 } 60 } 61 } 62 int res=INF; 63 for(int i=0; i<=tn; ++i) res=min(res,d[n][i]); 64 if(res==INF) printf("Case %d: %d\n",++t,-1); 65 else printf("Case %d: %d\n",++t,res); 66 } 67 return 0; 68 }
时间: 2024-12-28 09:41:09