1053. 修复DNA

题目链接

1053. 修复DNA

生物学家终于发明了修复DNA的技术,能够将包含各种遗传疾病的DNA片段进行修复。

为了简单起见,DNA看作是一个由’A’, ‘G’ , ‘C’ , ‘T’构成的字符串。

修复技术就是通过改变字符串中的一些字符,从而消除字符串中包含的致病片段。

例如,我们可以通过改变两个字符,将DNA片段”AAGCAG”变为”AGGCAC”,从而使得DNA片段中不再包含致病片段”AAG”,”AGC”,”CAG”,以达到修复该DNA片段的目的。

需注意,被修复的DNA片段中,仍然只能包含字符’A’, ‘G’ , ‘C’ , ‘T’。

请你帮助生物学家修复给定的DNA片段,并且修复过程中改变的字符数量要尽可能的少。

输入格式

输入包含多组测试数据。

每组数据第一行包含整数N,表示致病DNA片段的数量。

接下来N行,每行包含一个长度不超过20的非空字符串,字符串中仅包含字符’A’, ‘G’ , ‘C’ , ‘T’,用以表示致病DNA片段。

再一行,包含一个长度不超过1000的非空字符串,字符串中仅包含字符’A’, ‘G’ , ‘C’ , ‘T’,用以表示待修复DNA片段。

最后一组测试数据后面跟一行,包含一个0,表示输入结束。

输出格式

每组数据输出一个结果,每个结果占一行。

输入形如”Case x: y”,其中x为测试数据编号(从1开始),y为修复过程中所需改变的字符数量的最小值,如果无法修复给定DNA片段,则y为”-1”。

数据范围

1N50

输入样例:

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

输出样例:

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

解题思路

ac自动机+dp

  • 状态表示:f[i][j] 表示串的第 i 位字母对应ac自动机上的状态 j 时的不含模式串的最少修复数量

  • 状态计算:f[i+1][p]=min(f[i+1][p],f[i][j]),其中 i+1 上的状态 pi 上的状态 j 转移过来,为满足要求,要求状态节点 jp 不能为模式串对应的节点

  • 时间复杂度:O(20nm)

代码

// Problem: 修复DNA // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/1055/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1005; int trie[N][4],q[N],ne[N],n,idx,f[N][N]; bool dan[N]; char s[N]; int get(char c) { if(c=='A')return 0; if(c=='G')return 1; if(c=='C')return 2; return 3; } void insert() { int p=0; for(int i=0;s[i];i++) { int t=get(s[i]); if(!trie[p][t])trie[p][t]=++idx; p=trie[p][t]; } dan[p]=true; } void build() { int hh=0,tt=-1; for(int i=0;i<4;i++) if(trie[0][i])q[++tt]=trie[0][i]; while(hh<=tt) { int t=q[hh++]; for(int i=0;i<4;i++) { int p=trie[t][i]; if(!p)trie[t][i]=trie[ne[t]][i]; else { ne[p]=trie[ne[t]][i]; dan[p]|=dan[ne[p]]; q[++tt]=p; } } } } int main() { int T=0; while(cin>>n,n) { memset(dan,0,sizeof dan); idx=0; memset(trie,0,sizeof trie); memset(ne,0,sizeof ne); memset(f,0x3f,sizeof f); for(int i=1;i<=n;i++) { cin>>s; insert(); } build(); cin>>(s+1); int m=strlen(s+1); f[0][0]=0; for(int i=0;i<m;i++) for(int j=0;j<idx;j++) for(int k=0;k<4;k++) { int cost=get(s[i+1])!=k; int p=trie[j][k]; if(!dan[p]&&!dan[j])f[i+1][p]=min(f[i+1][p],f[i][j]+cost); } int res=0x3f3f3f3f; for(int i=0;i<idx;i++)res=min(res,f[m][i]); printf("Case %d: %d\n",++T,res==0x3f3f3f3f?-1:res); } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16001331.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(182)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示