判断基因的相似性的求解算法

题目描述:

众所周知,人类基因可以认为是一个基因序列,包含四种核苷酸,分别用ACGT4个字母简单地表示。生物学家对鉴别人类基因并确定他们的功能很感兴趣,因为这对诊断人类疾病和开发新药很有用。

给出两个基因AGTGATGGTTAG,他们有多相似呢?测量两个基因相似度的一种方法称为对齐。使用对齐方法,可以在基因的适当位置插进空格,让两个基因的长度相等,然后根据如下基因分值矩阵(注意:*号表示空格对空格是不允许的。)计算分数。

A

C

G

T

-

A

5

-1

-2

-1

-3

C

-1

5

-3

-2

-4

G

-2

-3

5

-2

-2

T

-1

-2

-2

5

-1

-

-3

-4

-2

-1

*

例如:给AGTGATG插入一个空格,就得到AGTGAT-G

GTTAG插入三个空格,就得到-GT--TAG

空格用减号(-)表示。现在两个基因一样长了,把这两个字符串对齐;

AGTGAT-G

-GT--TAG

对齐后,有4个基因是相配的:第二位的G,第三位的T,第六位的T和第八位的G。根据下列基因分值矩阵,没对匹配的字符都有相应的分值。

上面对齐的字符串分值是:(-3)+5+5+(-2)+(-3)+5+(-3)+5=9.

当然,还有其他的对齐方式。下面另一种对齐方式(不同数量的空格插进不同的位置):

AGTGATG

-GTTA-G

这种对齐方式的分值是(-3)+5+5+(-2)+5+(-1)+5=14,它比前一个要好。其实这种对齐方式是最优的,没有其他的方式能得到更高的分值了,所以这两个基因的相似度是14.

输入:

输入数据有T组测试样例,在第一个给出测试样例的个数(T)。每个测试用例有两行:每行有一个表示基因长度的整数和一个基因序列。每个基因序列的长度大于1不超过100.

输出:

输出每个测试样例的相似度,每行一个。

输入样列:

2

7 AGTGATG

5 GTTAG

7 AGCTATT

9 AGCTTTAAA

输出样列:

14

21

注(1. 从文件中读出题目的输入;2. 向屏幕上打印出题目的计算结果;)

 

是 

 通过c[i][j]=max{c[i-1][j-1]+init[s1[i-1]][s2[j-1])],c[i-1][j]+init[getback(s1[i-1])][4],c[i][j-1]+init[4][getback(s2[j-1])]} 获得每一个位置的相似值

  1. 其中初始化第一列时,其取值均来自上边,s1与空格匹配,其中标记一下b[i][j]是来自上边,值取为2:c[i][0]=c[i-1][0]+init[getback(s1[i-1])][4];当初始化第一行时,其取值均来自左边,s2与空格匹配,其中b[i][j]=2,标记来自左边:c[0][j]=c[0][j-1]+init[4][getback(s2[j-1])].
  2. 从i=1,j=1开始c[i][j]=max{c[i-1][j-1]+init[s1[i-1]][s2[j-1])],c[i-1][j]+init[getback(s1[i-1])][4],c[i][j-1]+init[4][getback(s2[j-1])]}
  3. 自底向上方法计算结果,用一个表记录他每次取值来源
  4. 其中c[s1l][s2l]为该问题的结果

根据矩阵b[][]来获得记录下的来源信息  其中1表示来自左上角,2表示来自上边,3表示来自左边

#include<iostream>
#include <algorithm>
using namespace std;

int s1l, s2l;
string s1, s2;
string m="", n="";
int getback(char c)
{
    if (c == 'A') return 0;
    if (c == 'C') return 1;
    if (c == 'G') return 2;
    if (c == 'T') return 3;
    return 4;

}
int init[5][5] = {
    {5,-1,-2,-1,-3},
    {-1,5,-3,-2,-4},
    {-2,-3,5,-2,-2},
    {-1,-2,-2,5,-1},
    {-3,-4,-2,-1,0}
};
int c[100][100] = { 0 };
int b[100][100] = { 0 };

int  zixulie()
{
   
    
     //初始化第一列,第一行
    for (int i = 1; i <=s1l; i++)
    {
        c[i][0] = c[i - 1][0] + init[getback(s1[i - 1])][4];
     //   cout << c[i][0] << " ";
       //来自上边
        b[i][0] = 2;
    }
    cout << endl;
    for (int j = 1; j <= s2l; j++)
    {
        c[0][j] = c[0][j - 1] + init[4][getback(s2[j - 1])];
       // cout << c[0][j] << " ";
        //来自左边
        b[0][j] = 3;
    }
    cout << endl;
    //计算最大相似度
    for (int i = 1; i <= s1l; i++)
    {
        for (int j = 1; j <=s2l; j++)
        {
            //左上角代表与左侧和上面的字符比对 相似度
            int leftup = c[i - 1][j - 1] + init[getback(s1[i - 1])][getback(s2[j - 1])];
            //上边 左侧与空格匹配
            int  up = c[i - 1][j] + init[getback(s1[i - 1])][4];
            //左边   上面与空格匹配
            int   left = c[i][j - 1] + init[4][getback(s2[j - 1])];
            c[i][j] = max({ leftup,up,left });
            if (c[i][j] == leftup)
            {
                b[i][j] = 1;
            }
            if (c[i][j] == up)
            {
                b[i][j] = 2;
            }
            if (c[i][j] == left)
            {
                b[i][j] = 3;
            }
              
           
        }
    }


  //  cout << s1 << endl;
   // cout << s2 << endl;
    for (int i = 0; i <= s2l; i++)
        cout <<" " << s2[i] << " ";
    cout << endl;
    for (int i = 0; i <= s1l; i++)
    {
        
        for (int j = 0; j <=s2l; j++)
        {
             
            cout << c[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
    for (int i = 0; i <= s1l; i++)
    {

        for (int j = 0; j <= s2l; j++)
        {

            cout << b[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
    int i = s1l, j = s2l;
    while (b[i][j] != 0)
    {
        switch (b[i][j])
        {
        case 1:
            //左上角
            m += s1[i - 1];
            n += s2[j - 1];
            i--;
            j--;
            break;
        case 2://上边
            m += s1[i - 1];
            n += '-';
            i--;
            break;
        case 3:
            n += s2[j - 1];
            m += '-';
            j--;
            break;

        default:
            break;
        }
    }
    for (int i = m.length() - 1; i >= 0; i--)
        cout << m[i];
    cout << endl;
    for (int i = n.length(); i >= 0; i--)
        cout << n[i];
    cout << endl;

        return c[s1l][s2l];
}

//来自上面的单元格,代表将左侧的字符与空格比对。
//来自左侧的单元格,代表将上面的字符与空格比对。
//来自左上侧的单元格,代表与左侧和上面的字符比对(可能匹配也可能不匹配)


int main()
{
    
    int n;
    cout << "输入样例测试个数:" << endl;
    cin >> n;
    for (int i = 0; i < 2; i++)
    {
        cin >> s1l >> s1;
        cin >> s2l >> s2;
     cout<<zixulie()<<endl;
      
       
       
    }
    
    




}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值