问题描述:
已知:有两给定序列str1和str2,序列只由{'A', 'C', 'G', 'T'}组成。现在序列中插入空格(用'-'表示),由于‘-’可表示任意字符,故上述插入操作可使str1=str2,例如:
str1:AGTGATG
str2:GTTAG
插入'-‘后变为:
str1:AGTGAT-G
str2:-GT--TAG
另外,str1和str2对应位置的一对字符有固定权值,如下图所示。定义相似度为:所有字符对的权值之和

求:插入'-'可获得的最大相似度
输入:第1行为n;之后为n个case,每个case占两行,每行由一个正整数(代表str长度)和一个字符串(代表str)组成
输出:可获得的最大相似度
Sample Input:
2
7 AGTGATG
5 GTTAG
7 AGCTATT
9 AGCTTTAAA
Sample Output:
14
21
思路:
首先,将可获得最大相似度的已插入序列对从某处切开,易知若要使总体相似度最大,左右两子部分的相似度也必须最大,即具有最优子结构
记e(i, j)为以子序列str1(1, i)和str2(1, j)为输入所得的最大相似度,则有如下递归表达式

原问题最优解即为e(n1, n2)
代码:
#include <stdio.h>
#include <limits.h>
int score[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}
};
char str1[110], str2[110];
int seq1[110], seq2[110]; //将输入的字符序列转换为对应于score数组的下标索引,方便后面查询权值
int case_n;
int n1, n2;
void dp(){
int e[110][110];
e[0][0] = 0; //初始化
for(int i = 1; i <= n1; i++)
e[i][0] = e[i-1][0]+score[seq1[i]][4];
for(int j = 1; j <= n2; j++)
e[0][j] = e[0][j-1]+score[4][seq2[j]];
for(int i = 1; i <= n1; i++){
for(int j = 1; j <= n2; j++){
e[i][j] = e[i-1][j]+score[seq1[i]][4];
e[i][j] = (e[i][j-1]+score[4][seq2[j]] > e[i][j]) ? e[i][j-1]+score[4][seq2[j]] : e[i][j];
e[i][j] = (e[i-1][j-1]+score[seq1[i]][seq2[j]] > e[i][j]) ? e[i-1][j-1]+score[seq1[i]][seq2[j]] : e[i][j];
}
}
printf("%d\n", e[n1][n2]);
}
int main(){
scanf("%d", &case_n);
for(int i = 0; i < case_n; i++){
scanf("%d%s", &n1, str1);
for(int j = 0; j < n1; j++){
switch(str1[j]){
case 'A':
seq1[j+1] = 0;
break;
case 'C':
seq1[j+1] = 1;
break;
case 'G':
seq1[j+1] = 2;
break;
case 'T':
seq1[j+1] = 3;
break;
default:
break;
}
}
scanf("%d%s", &n2, str2);
for(int j = 0; j < n2; j++){
switch(str2[j]){
case 'A':
seq2[j+1] = 0;
break;
case 'C':
seq2[j+1] = 1;
break;
case 'G':
seq2[j+1] = 2;
break;
case 'T':
seq2[j+1] = 3;
break;
default:
break;
}
}
dp();
}
return 0;
}
本文介绍了一种利用动态规划解决序列比对问题的方法,通过插入特殊字符来提高两个序列的相似度,并给出了具体的实现代码。
1372

被折叠的 条评论
为什么被折叠?



