题意:
已知一个DNA串和一些病毒DNA序列,求出最少改变DNA串中多少个字符,能使得串中不包含任意一个病毒序列。
题解:
嗯,和上一个trie图一样,把病毒建成trie,只要母串不能再trie上走到危险节点即可(危险节点就是病毒dna序列的终止的那个被标有fg的节点)。
然后trie图上的dp,要走到危险节点的时候,枚举转移即可。
View Code
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <algorithm> 6 7 #define M 1111 8 #define N 111 9 #define INF 0x3f3f3f3f 10 11 using namespace std; 12 13 struct TR 14 { 15 int son[4]; int f; bool fg; 16 }tr[N*N]; 17 18 int map[N],cnt,q[N*N],n,m,cas; 19 char str[N],a[M]; 20 int dp[M][N*N]; 21 22 inline void insert(char *s) 23 { 24 int len=strlen(s+1); 25 int now=1; 26 for(int i=1;i<=len;i++) 27 { 28 if(!tr[now].son[map[s[i]]]) tr[now].son[map[s[i]]]=++cnt; 29 now=tr[now].son[map[s[i]]]; 30 } 31 tr[now].fg=true; 32 } 33 34 inline void build() 35 { 36 int h=1,t=2,sta,now,tmp; 37 q[1]=1; 38 while(h<t) 39 { 40 sta=q[h++]; 41 for(int i=0;i<4;i++) 42 { 43 now=tr[sta].son[i]; 44 if(sta==1) tmp=1; 45 else tmp=tr[tr[sta].f].son[i]; 46 if(now==0) tr[sta].son[i]=tmp; 47 else 48 { 49 tr[now].f=tmp; tr[now].fg|=tr[tmp].fg; 50 q[t++]=now; 51 } 52 } 53 } 54 } 55 56 inline void read() 57 { 58 memset(tr,0,sizeof tr); 59 tr[cnt=1].f=1; 60 for(int i=1;i<=n;i++) 61 { 62 scanf("%s",str+1); 63 insert(str); 64 } 65 scanf("%s",a+1); 66 m=strlen(a+1); 67 build(); 68 } 69 70 inline void go() 71 { 72 memset(dp,0x3f,sizeof dp); 73 dp[0][1]=0; 74 for(int i=0;i<m;i++) 75 for(int j=1;j<=cnt;j++) 76 { 77 for(int k=0;k<4;k++) 78 if(!tr[tr[j].son[k]].fg) dp[i+1][tr[j].son[k]]=min(dp[i+1][tr[j].son[k]],dp[i][j]+1); 79 if(!tr[tr[j].son[map[a[i+1]]]].fg) dp[i+1][tr[j].son[map[a[i+1]]]]=min(dp[i+1][tr[j].son[map[a[i+1]]]],dp[i][j]); 80 } 81 int ans=INF; 82 for(int i=1;i<=cnt;i++) ans=min(ans,dp[m][i]); 83 if(ans==INF) ans=-1; 84 printf("Case %d: %d\n",++cas,ans); 85 } 86 87 int main() 88 { 89 map['A']=0; map['G']=1; map['C']=2; map['T']=3; 90 while(scanf("%d",&n),n) read(),go(); 91 return 0; 92 }