题目描述:
众所周知,人类基因可以认为是一个基因序列,包含四种核苷酸,分别用A,C,G和T4个字母简单地表示。生物学家对鉴别人类基因并确定他们的功能很感兴趣,因为这对诊断人类疾病和开发新药很有用。 给出两个基因AGTGATG和GTTAG,他们有多相似呢?测量两个基因相似度的一种方法称为对齐。使用对齐方法,可以在基因的适当位置插进空格,让两个基因的长度相等,然后根据如下基因分值矩阵(注意:*号表示空格对空格是不允许的。)计算分数。
例如:给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])]} 获得每一个位置的相似值
- 其中初始化第一列时,其取值均来自上边,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])].
- 从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])]}
- 自底向上方法计算结果,用一个表记录他每次取值来源
- 其中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;
}
}