hihoCoder 1052-基因工程
#1052 : 基因工程
时间限制:1000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi和小Ho正在进行一项基因工程实验。他们要修改一段长度为N的DNA序列,使得这段DNA上最前面的K个碱基组成的序列与最后面的K个碱基组成的序列完全一致。
例如对于序列”ATCGATAC”和K=2,可以通过将第二个碱基修改为”C”使得最前面2个碱基与最后面两个碱基都为”AC”。当然还存在其他修改方法,例如将最后一个碱基改为”T”,或者直接将最前面两个和最后面两个碱基都修改为”GG”。
小Hi和小Ho希望知道在所有方法中,修改碱基最少的方法需要修改多少个碱基。
输入
第一行包含一个整数T(1 <= T <= 10),代表测试数据的数量。
每组测试数据包含2行,第一行是一个由”ATCG”4个大写字母组成的长度为N(1 <= N <= 1000)的字符串。第二行是一个整数K(1 <= K <= N)。
输出
对于每组数据输出最少需要修改的碱基数量。
样例输入
2
ATCGATAC
2
ATACGTCT
6
样例输出
1
3
简单的字符串处理题目,该题要求修改字符保证前k个字符和后k个字符相同,求最小的修改次数。这个题目会让人想到字符串的编辑距离,但不完全相同,因为这题是对单个字符串的修改,不能想当然的把前后k个字符取出来,然后逐一比较是否相等,因为如果前k个字符和后k个字符有重叠的话,你修改了某个字符,会影响下一次比较。
比如字符串CTACATGT,长度n=8,k=6,前k个字符串为s1=CTACAT,后k个字符串为s2=ACATGT,我们不能单独求s1和s2的距离,而是需要把这些字符放到原字符串中,再进一步研究你会发现其实就是在原字符串中保证s[i]=s[i+2],其中2=d=n-k。也就是下图中红色和绿色的两组字符要分别相同。

现在我们分析红色那组字符,首先s[0]==s[2]不成立,可以把s[0]改成A;也可以把s[2]改成C,如果我们把s[2]改成C的话,虽然s[0]==s[2]成立,但是s[2]==s[4]又不成立了,又要修改s[4];但是如果我们把s[0]改成A的话,则s[0]==s[2]==s[4]都成立,且修改次数更少。那么要怎样才能使修改的次数最少呢?
我们回到问题的本源:使用红色那组字符都相同,为了使修改次数最少,我们当然是将所有字符统一成当前出现次数最多的那个字符咯,这样只需要修改较少的非同一字符,在这个例子中,就是修改成出现次数最多的A。
如果前k个字符串和后k个字符串没有重叠,那就很简单了,只需依次检查对应字符是否相等。
理解了以上内容,代码很快就能写出来了:
[cpp]
#include<iostream>
#include<string>
using namespace std;
//求4个数的最大值
int max4(int a,int b,int c,int d)
{
int maxab=a>b?a:b;
int maxcd=c>d?c:d;
return maxab>maxcd?maxab:maxcd;
}
int main()
{
int t,k,n,d,ans;//t,k为题意;n为字符串长度;d为n-k相隔为d的字符需要相等;ans表示需要修改的碱基数量。
string s;
cin>>t;
while(t–)
{
ans=0;
cin>>s>>k;
n=s.size();
d=n-k;
if(2*k<=n)//如果最前k个碱基和最后k个碱基没有重叠的话
{
for(int i=0;i<k;i++)
if(s[i]!=s[i+d])//只需要依次检查对应字符是否相等即可
ans++;
}
else//如果有重叠,则另行讨论
{
for(int i=0;i<d;i++)//把所有碱基分成d组,需要确保每组都是同一个字符
{
int A=0,T=0,G=0,C=0,num=0;
for(int j=i;j<n;j+=d)//对于每一组,求出该组中出现次数最多的碱基的个数
{
num++;
if(s[j]==’A’)
A++;
else if(s[j]==’T’)
T++;
else if(s[j]==’G’)
G++;
else
C++;
}
int maxATGC=max4(A,T,G,C);//该组全部修改成出现次数最多的碱基
int change_num=num-maxATGC;//用该组中所有碱基个数减去出现次数最多的碱基个数,就是需要修改的碱基个数
ans+=change_num;
}
}
cout<<ans<<endl;
}
return 0;
}
[/cpp]
本代码提交AC,用时1MS,内存0MB。
]]>