[HNOI2002]DNA分子的最佳比对

看着网上没有人写这道题的博客,洛谷上也只有十几个人AC,我不妨尝试了这道题!

题解基本没有!

任何一个伟大的思想,都有一个微不足道的开始。

题目描述

DNA分子是人类遗传信息的载体,它间接地指导蛋白质的合成。DNA分子是由四种核苷酸组成的长链,这四种核苷酸分别是腺嘌呤核苷酸(用A代表)、鸟嘌呤核苷酸(用G代表)、胞嘧啶核苷酸(用C代表)和胸腺嘧啶核苷酸(用T代表)。习惯上用一个字符集为{A,T,C,G}的字符串来表示一个DNA分子序列,如CGTTAGA。

在生物进化过程中,DNA分子可能发生各种各样的突变。这种突变形成了生物遗传信息的改变,从而使生物得以分化,构成了生物的多样性。主要的突变有三种:(1)在一个DNA序列中插入一个新的核苷酸,(2)DNA序列中丢失了一个核苷酸,(3)DNA序列中的某个核苷酸被另一个核苷酸所取代。

所谓两个DNA序列的一个比对是寻找一种排列方式,使得两个DNA序列在同样的位置上有相同的核苷酸,而若在同样的位置上两个DNA序列的核苷酸不同,则是由三种突变之一得到。例如,对两个DNA序列T =ATCAG,T =ACTAG,可以按如下方式比对,

比对1:

T1 T2

A A T --- (T2 的该位置由T1 丢失一个核苷酸T得到,“--”表示空白)

C C

--- T (T2 的该位置由T1 插入一个核苷酸T得到)

A A

G G

也可以按如下方式比对

比对2:

T1 T2

A A

T C (T2 的该位置用一个C取代 T1 的T)

C T (T2 的该位置用一个T1取代T 的C)

A A

G G

如果两个DNA序列在相同的位置上有越多相同的核苷酸对,则表明它们之间越相似,即它们存在功能上的相似性和进化史上的亲缘关系。

对于两个DNA序列的一个比对,规定如下得分方式:(1)一个同样的位置上有相同的核苷酸对,则可得1分;(2)一个同样的位置上有不同的核苷酸对,则得0分;(3)如果在某个位置上一个序列有核苷酸,而另一个序列在该位置上为“--”,则得-2分。例如,比对1的得分是0分,比对2的得分是3分。

问题是:对于两个DNA序列,寻找一种比对方式,使得它们的得分最高。

输入输出格式

输入格式:

 

输入数据由文件名为INPUT.*的文本文件提供,共有2行。

第1行为DNA序列T1 , 第2行为DNA序列T2 。序列的长度不大于1000。序列中的字母是英文小写或者大写字母。

 

输出格式:

 

程序运行结束时,在屏幕上输出所找出的最大的得分

 

输入输出样例

输入样例: 
Atcag
Actag
输出样例: 
3



这道题我调了好久才调出来,悲惨qwq

讲一讲思路吧!
正经点!

这道题要懂,恐怕LCS算法也要懂,链接:https://www.cnblogs.com/wangshengjun/p/LCS.html
这是比LCS多一点复杂一点。
f[i][j]表示第一个字符匹配到i的,第二个字符匹配到j的最优值。
f[i][j]有三种情况转移:
第一种是 i 不变 ,j 向后移一格 , 则值 减二。(如题:如果在某个位置上一个序列有核苷酸,而另一个序列在该位置上为“--”,则得-2分。例如,比对1的得分是0分,比对2的得分是3分。)
代码如下:
f[i][j-1]-2
          第二种是 j不变,i向后移一格,则值减二。(如题:如果在某个位置上一个序列有核苷酸,而另一个序列在该位置上为“--”,则得-2分。例如,比对1的得分是0分,比对2的得分是3分。)
代码如下:
f[i-1][j]-2

                             第三种是i,j 同时向后移一格,当两串相同时+1,否则,不更新值。

                                  代码如下:

f[i-1][j-1]+(s1[i]==s2[j]?1:0)

        结合之后状态转移方程就产生了!

f[i][j]=max(f[i-1][j-1]+(s1[i]==s2[j]?1:0),f[i-1][j]-2,f[i][j-1]-2)

 

                   用状态转移方程转换成二维图:
                                                        

 

      但还需要预处理一下,把f[i][j]的初始值赋值为(0,-2,-4,-6,-8 ,......(如此规律));
                        人间就是这么简单,这么奇怪!

 

                        加上之后,万事大吉了— — AC 了。

70~70~70~ WA了3个点。

              

 

          最后,废话不多说,放代码!!!

                          

#include<bits/stdc++.h>
int f[1039][1039],ans=-2147483648,flag;
char s1[1039],s2[1039];
int max(int a,int b,int c){return std::max(a,std::max(b,c));}
int main(){
    scanf("%s%s",s1+1,s2+1);
    int l1=strlen(s1+1);int l2=strlen(s2+1),tmp=0,l = std::max(l1,l2);
    for(int i=0;i<l+1;i++){
    	f[i][0]=tmp;
    	f[0][i]=tmp;
    	tmp-=2;
	}f[0][0] = 0;
    for(int i = 1; i < l1+1; i++)
        for(int j = 1; j < l2+1; j++){
            if(s1[i]==s2[j])flag = 1;
            else flag = 0;
            f[i][j] = max(f[i-1][j-1]+flag, f[i-1][j]-2, f[i][j-1]-2);
        }
    ans = std::max(ans, f[l1][l2]);
    printf("%d", ans);
    return 0;
}

 

  小心字符串,很肯人的。

难道这道题就这么难么?
祝大家RP++!

OVER!

       

 


                




posted @ 2018-11-27 19:11  DATA-P  阅读(1106)  评论(1编辑  收藏  举报