DNA repair
题意:有些DNA序列是致病的,给你以个长DNA序列,问最少需要修改多少次使得其不含致病序列。
好多题解说的不清不楚的。。。最关键的地方往往没说清楚。。。
首先是进行了一步转换,将其理解为在建好的Trie图上走len(序列长度)步,走的路不能包含致病序列。
然后就变成了一个dp,d[i][j]表示第i步走到j节点最少需要修改几次。那么要看所有能走到j节点的点,如果和s[i-1]相同,就不用修改,如果不同,修改次数加一,取较小的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR(m,a) memset(m,a,sizeof(m)) 4 const int inf=0x3f3f3f3f; 5 const int maxnode=50*20+10; 6 const int sigma=4; 7 8 struct AC{ 9 int ch[maxnode][sigma],f[maxnode]; 10 int match[maxnode]; 11 int sz; 12 int mp[128]; 13 14 void init(){ 15 CLR(match,0); 16 mp['A']=0;mp['G']=1;mp['C']=2;mp['T']=3; 17 CLR(ch[0],0); 18 sz=1; 19 } 20 void inser(char *s){ 21 int u=0,n=strlen(s); 22 for(int i=0;i<n;i++){ 23 int c=mp[s[i]]; 24 if(!ch[u][c]){ 25 CLR(ch[sz],0); 26 ch[u][c]=sz++; 27 } 28 u=ch[u][c]; 29 } 30 match[u]=1; 31 } 32 void getfail(){ 33 queue<int> q; 34 f[0]=0; 35 match[0]=0; 36 for(int c=0;c<sigma;c++){ 37 int u=ch[0][c]; 38 if(u){ 39 q.push(u); 40 f[u]=0; 41 } 42 } 43 while(!q.empty()){ 44 int r=q.front(); 45 q.pop(); 46 for(int c=0;c<sigma;c++){ 47 int u=ch[r][c]; 48 if(!u){ 49 ch[r][c]=ch[f[r]][c]; 50 continue; 51 } 52 q.push(u); 53 int v=f[r]; 54 while(v&&!ch[v][c]) v=f[v]; 55 f[u]=ch[v][c]; 56 match[u]|=match[f[u]]; 57 } 58 } 59 } 60 }; 61 AC ac; 62 char s[maxnode]; 63 int len; 64 int dp[maxnode][maxnode]; 65 66 void DP(){ 67 CLR(dp,inf); 68 dp[0][0]=0; 69 for(int i=1;i<=len;i++){ 70 for(int j=0;j<ac.sz;j++){ 71 if(ac.match[j]) continue; 72 for(int c=0;c<sigma;c++){ 73 if(ac.match[ac.ch[j][c]]) continue; 74 dp[i][ac.ch[j][c]]=min(dp[i][ac.ch[j][c]],dp[i-1][j]+(ac.mp[s[i-1]]!=c)); 75 } 76 } 77 } 78 } 79 int main(){ 80 int n; 81 int kase=0; 82 while(scanf("%d",&n)!=EOF&&n){ 83 ac.init(); 84 for(int i=0;i<n;i++){ 85 scanf("%s",s); 86 ac.inser(s); 87 } 88 ac.getfail(); 89 scanf("%s",s); 90 len=strlen(s); 91 DP(); 92 int ans=inf; 93 for(int i=0;i<ac.sz;i++)if(!ac.match[i]){ 94 ans=min(dp[len][i],ans); 95 } 96 if(ans==inf) ans=-1; 97 printf("Case %d: %d ",++kase,ans); 98 } 99 return 0; 100 }