题意:先给出m个DNA片段(含致病基因),然后给一个长为n的DNA序列,求最少需要修改多少次,使得这个DNA序列不含致病基因。修改操作定义为将DNA中某个碱基变为另一个碱基,如将A变为G
数据范围:1<=m<=50,1<=n<=1000
分析:先建自动机,然后DP。
状态设计:dp[i][j]为从根结点出发走 i 步后到达状态 j 最少需要修改的次数。
状态转移:
1、dp[i][j]=MIN(dp[i-1][k]),从状态k能根据s[i]跳到状态j,无需修改;
2、dp[i][j]=MIN(dp[i-1][k])+1,从状态k不能根据s[i]跳到状态j,需要修改s[i]。(注意区分DP的状态和自动机的状态)
初始化:dp[0][0]=0,其余的dp[0][i]=INF.
View Code
#include <stdio.h> #include <string.h> #include <queue> using namespace std; #define N 51 #define LEN 21 #define INF 0x3f3f3f3f #define MIN(a,b) ((a)<(b)?(a):(b)) int next[N*LEN][4]; int fail[N*LEN]; bool flag[N*LEN]; int n,node; int dp[1010][N*LEN]; char s[1010]; int len; void init() { node=1; memset(next[0],0,sizeof(next[0])); } void add(int cur,int k) { memset(next[node],0,sizeof(next[node])); flag[node]=0; next[cur][k]=node++; } int hash(char c) { switch(c) { case 'A': return 0; case 'C': return 1; case 'G': return 2; case 'T': return 3; } } void insert(char *s) { int i,cur,k; for(i=cur=0; s[i]; i++) { k=hash(s[i]); if(!next[cur][k]) add(cur,k); cur=next[cur][k]; } flag[cur]=1; } void build_ac() { queue<int>q; int cur,nxt,tmp; fail[0]=0; q.push(0); while(!q.empty()) { cur=q.front(),q.pop(); for(int k=0; k<4; k++) { nxt=next[cur][k]; if(nxt) { if(!cur) fail[nxt]=0; else { for(tmp=fail[cur]; tmp && !next[tmp][k]; tmp=fail[tmp]); fail[nxt]=next[tmp][k]; } if(flag[fail[nxt]]) flag[nxt]=1; q.push(nxt); } else next[cur][k]=next[fail[cur]][k]; } } } void solve() { memset(dp,0x3f,sizeof(dp)); dp[0][0]=0; len=strlen(s+1); for(int step=1; step<=len; step++) { for(int pre=0; pre<node; pre++) { if(flag[pre]) continue; for(int k=0; k<4; k++) { int cur=next[pre][k]; if(hash(s[step])==k) { dp[step][cur]=MIN(dp[step-1][pre],dp[step][cur]); } else { dp[step][cur]=MIN(dp[step-1][pre]+1,dp[step][cur]); } } } } int ans=INF; for(int state=0; state<node; state++) { if(!flag[state]) { ans=MIN(ans,dp[len][state]); } } if(ans<INF) printf("%d\n",ans); else puts("-1"); } int main() { int kase=0; while(scanf("%d",&n),n) { init(); for(int i=0; i<n; i++) { scanf("%s",s); insert(s); } scanf("%s",s+1); build_ac(); printf("Case %d: ",++kase); solve(); } return 0; }