【POJ3691】 DNA repair (AC自动机+DP)

DNA repair

Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u

Description

Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters ‘A‘, ‘G‘ , ‘C‘ and ‘T‘. The repairing techniques are simply to change some characters to eliminate all segments causing diseases. For example, we can repair a DNA "AAGCAG" to "AGGCAC" to eliminate the initial causing disease segments "AAG", "AGC" and "CAG" by changing two characters. Note that the repaired DNA can still contain only characters ‘A‘, ‘G‘, ‘C‘ and ‘T‘.

You are to help the biologists to repair a DNA by changing least number of characters.

Input

The input consists of multiple test cases. Each test case starts with a line containing one integers N (1 ≤ N ≤ 50), which is the number of DNA segments causing inherited diseases. 
The following N lines gives N non-empty strings of length not greater than 20 containing only characters in "AGCT", which are the DNA segments causing inherited disease. 
The last line of the test case is a non-empty string of length not greater than 1000 containing only characters in "AGCT", which is the DNA to be repaired.

The last test case is followed by a line containing one zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the 
number of characters which need to be changed. If it‘s impossible to repair the given DNA, print -1.

Sample Input

2
AAA
AAG
AAAG
2
A
TG
TGAATG
4
A
G
C
T
AGT
0

Sample Output

Case 1: 1
Case 2: 4
Case 3: -1

【题意】

  已知一个DNA串和一些病毒DNA序列,求出最少改变DNA串中多少个字符,能使得串中不包含任意一个病毒序列。

【分析】

  建AC自动机然后DP,不要走到有标记的点即可。

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 3010
  9 #define Maxl 1010
 10 #define INF 0xfffffff
 11
 12 int n;
 13 char s[20];
 14 char ss[Maxl];
 15
 16 struct node
 17 {
 18     int cnt,fail;
 19     bool mark;
 20     int son[5];
 21 }t[Maxn];int tot;//=0;
 22
 23 void upd(int x)
 24 {
 25     t[x].cnt=1;t[x].mark=0;
 26     memset(t[x].son,0,sizeof(t[x].son));
 27 }
 28
 29 int mymin(int x,int y) {return x<y?x:y;}
 30
 31 void read_trie()
 32 {
 33     scanf("%s",s+1);
 34     int len=strlen(s+1);
 35     int now=0;
 36     for(int i=1;i<=len;i++)
 37     {
 38         int ind=s[i]-‘A‘+1;
 39         if(ind==3) ind=2;
 40         else if(ind==7) ind=3;
 41         else if(ind==20) ind=4;
 42         if(!t[now].son[ind])
 43         {
 44             t[now].son[ind]=++tot;
 45             upd(tot);
 46         }
 47         now=t[now].son[ind];
 48         if(i==len) t[now].mark=1;
 49     }
 50 }
 51
 52 queue<int > q;
 53 // bool inq[Maxn];
 54 void build_AC()
 55 {
 56     while(!q.empty()) q.pop();
 57     q.push(0);//inq[0]=1;
 58     while(!q.empty())
 59     {
 60         int x=q.front();q.pop();
 61         for(int i=1;i<=4;i++)
 62         {
 63             if(t[x].son[i])
 64             {
 65                 t[t[x].son[i]].fail=x?t[t[x].fail].son[i]:0;
 66                 q.push(t[x].son[i]);
 67             }
 68             else t[x].son[i]=t[t[x].fail].son[i];
 69             if(t[t[x].fail].mark) t[x].mark=1;
 70         }
 71     }
 72 }
 73
 74 int f[Maxn][Maxl];
 75 void dp()
 76 {
 77     scanf("%s",ss+1);
 78     int len=strlen(ss+1);
 79     for(int i=1;i<=len;i++)
 80     {
 81         if(ss[i]==‘C‘) ss[i]=‘B‘;
 82         else if(ss[i]==‘G‘) ss[i]=‘C‘;
 83         else if(ss[i]==‘T‘) ss[i]=‘D‘;
 84     }
 85     memset(f,63,sizeof(f));
 86     f[0][0]=0;
 87     for(int i=1;i<=len;i++)
 88      for(int j=0;j<=tot;j++) if(f[i-1][j]<INF)
 89      {
 90          for(int k=1;k<=4;k++) if(!t[t[j].son[k]].mark)
 91          {
 92              if(ss[i]-‘A‘+1==k)
 93               f[i][t[j].son[k]]=mymin(f[i][t[j].son[k]],f[i-1][j]);
 94              else f[i][t[j].son[k]]=mymin(f[i][t[j].son[k]],f[i-1][j]+1);
 95          }
 96      }
 97     int ans=INF;
 98     for(int i=0;i<=tot;i++) ans=mymin(f[len][i],ans);
 99     if(ans<=len) printf("%d\n",ans);
100     else printf("-1\n");
101 }
102
103 void init()
104 {
105     tot=0;
106     upd(0);
107     for(int i=1;i<=n;i++)
108     {
109         read_trie();
110     }
111     build_AC();
112 }
113
114 int main()
115 {
116     int kase=0;
117     while(1)
118     {
119         scanf("%d",&n);
120         if(n==0) break;
121         init();
122         printf("Case %d: ",++kase);
123         dp();
124     }
125     return 0;
126 }

[POJ3691]

2016-07-11 10:06:17

时间: 2024-09-30 11:45:46

【POJ3691】 DNA repair (AC自动机+DP)的相关文章

POJ 3691 DNA repair AC自动机 + DP

题意:给你只包含‘A’,‘G’,‘T’,‘C’四个字母的n个模板串和1个文本串,问你文本串改变多少个字符就可以使得文本串中没有一个模板串 解题思路: 我们可以知道  dp[i][j] 为文本串到 第i 个字符  AC自动机状态为j的最少的变换次数(这里为什么要用AC自动机,因为end数组可以记录哪一个状态是结束的,而且处理以后可以知道那些后缀等于前缀--也就是不能到达,因为如果能够到达的话那么状态更新就会产生错误.),这样dp即可 解题代码: 1 // File Name: temp.cpp 2

HDU 2457 DNA repair AC自动机 + dp

http://acm.hdu.edu.cn/showproblem.php?pid=2457 首先把病毒串保存一下,然后对于每一个trie上的节点,跑一发AC自动机,建立一个trie图. 建立的时候,对应做一些修改. 比如,现在建立成了这个样子. 如果he是一个病毒串,那么应该相对应的,把she那个he的位置,标志上,它也是病毒串,也就是不能转移到这一个状态. 这个可以在buildfail的时候对应修改. dp, 设dp[i][j],表示处理到字符串的第i个,走到了AC自动机的第j个节点,变成了

POJ 3691 &amp; HDU 2457 DNA repair (AC自动机,DP)

http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5690   Accepted: 2669 Description Biologists finally invent techniques of repairing DNA that contain

poj3691--DNA repair(AC自动机+dp)

DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5743   Accepted: 2693 Description Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a

hdu2457---DNA repair(AC自动机+dp)

Problem Description Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters 'A', 'G' , 'C' and 'T'. The repai

HDU 2457 DNA repair (AC自动机 + DP)

题目链接:DNA repair 解析:给出n个致病DNA序列,给一段DNA片段,问最少修改多少个碱基才能修复这段DNA序列中的所有致病序列. AC自动机 + DP. 将n个致病DNA序列构成一个自动机. 令DP[i][j]表示长度为i走到节点j是所需改变的最少个数. 状态转移时,枚举下一步所有可能的碱基,然后判断该碱基是否达到匹配状态,若能,则安全转移,继续枚举下一个碱基:否则在不匹配的前提下,看该碱基加入之后是否跟上一状态相同,若不同,则需修复,即计数加一.若相同,直接转移即可.然后选择其中最

HDU2457 DNA repair(AC自动机+DP)

题目一串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<que

hdu 2457 AC自动机+dp

DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2004    Accepted Submission(s): 1085 Problem Description Biologists finally invent techniques of repairing DNA that contains segments c

HDU3341 Lost&#39;s revenge(AC自动机+DP)

题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数论基因数 其中ACGT可以hash成一个整数(a*C*G*T+c*G*T+g*T+T),这样用二维数组就行了,而第二维最多也就11*11*11*11个. 接下来转移依然是我为人人型,我是丢进一个队列,用队列来更新状态的值. 这题果然挺卡常数的,只好手写队列,最后4500msAC,还是差点超时,代码也

Hdu 3341 Lost&#39;s revenge (ac自动机+dp+hash)

题目大意: 给出很多个DNA串,每一个串的价值为1,最后给出一个长串,要你重新排列最后的串使之它所有的子串的权值和最大. 思路分析: 最先容易想到的思路就是搜!管她3721..直接一个字符一个字符的码,然后在AC自动机上判断最后的权值.TLE哟. 然后发现搜过不去,那就dp咯.再容易想到的就是dp[i][a][b][c][d] 表示此时遍历AC自动机的节点在i,然后构成了a个A,b个G,c个C,d个T的权值. 再一看内存,500*40*40*40*40...然后...就没有然后了 再想,因为它说