题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1080
题目大意:基因序列里面有四个字符ACTG,对于个基因序列,从中插入“-”符号让两个基因序列一样长。对于ACGT-这五个符号,任意两个符号都有一个对应的得分,给定一个对应符号的得分矩阵,求两个基因序列插入-符号以后得分的最大值。
例如:AGTGATG和GTTAG这两个基因序列,插入-符号使两个基因序列等长,AGTGAT-G和-GT--TAG是其中一种方案,在这种方案中,A对应-,G对应G,T对应T,G对应-,A对应-。。。。。。。根据对应元素的矩阵计算总得分。我们的目标是计算得分的最大值。
本题如果暴力解,列出所有可能插入-符号的情况,计算量非常大,根本行不通,而且会产生大量的子问题的重复计算。所以本题选用动态规划的方法来做。
首先,动态规划问题都是做出某种选择(一般通过遍历来确定哪种选择是最优的选择),确定了规模更小的子问题。通过子问题构建和原问题的递推关系式,进而求解原问题(一般采取自底向上的方法)。
我们以TAGCTAG和ATTGC这两个基因序列为例,设f[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最大得分,我们的目标是求f[7][5]。当插入-符号两个序列等长以后,最后一个元素只有三种可能:
1、G对应C,此时产生子问题f[6][4]。此时f[7][5]=GC对应的分数+f[6][4]
2、G对应-,此时产生子问题f[6][5]。此时f[7][5]=G-对应的分数+f[6][5]
3、-对应C,此时产生子问题f[7][4]。此时f[7][5]=-C对应的分数+f[7][4]
f[7][5]等于三者的最大值。
采用自底向上求解的过程中,f[0][i]和f[i][0](i任意)所为初始条件,f[0][0]=0,举个例子f[0][2]就等于--和AT的得分(由于第一个序列没有元素)。
附上我的求解程序:
#include<iostream>
#include<string>
#include<climits>
using namespace std;
#define DEBUG
#define MAX(a,b) (a)>(b)?(a):(b)
//A:0,C:1,G:2,T:3,-:4
int score_matrix[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,INT_MIN},
};
int T;
int f[105][105];//f[i][j]表示gene[0]的前i个元素和gene[1]的前j个元素最大数
void initf(int& len0,string& gen0,int& len1,string& gen1);
int getIndex(char ch);
int main(){
cin>>T;
int len[2];
string gene[2];
string s;
while(T--){
cin>>len[0]>>gene[0]>>len[1]>>gene[1];
initf(len[0],gene[0],len[1],gene[1]);
string::iterator iter0=gene[0].begin();
string::iterator iter1=gene[1].begin();
char char0,char1;
int x,y;
for(int i=1;i<=len[0];i++){
for(int j=1;j<=len[1];j++){
//计算f[i][j],gene[0]的前i个字符和gene[1]的前j个字符的最大值
char0=*(iter0+i-1);//gene[0]第i个字符
char1=*(iter1+j-1);//gene[1]第j个字符
x=getIndex(char0);
y=getIndex(char1);
f[i][j]=MAX(f[i][j],f[i-1][j-1]+score_matrix[x][y]);
f[i][j]=MAX(f[i][j],f[i-1][j]+score_matrix[x][4]);
f[i][j]=MAX(f[i][j],f[i][j-1]+score_matrix[y][4]);
}
}
cout<<f[len[0]][len[1]]<<endl;
}
}
void initf(int& len0,string& gen0,int& len1,string& gen1){
for(int i=0;i<105;i++){
for(int j=0;j<105;j++)
f[i][j]=INT_MIN;
}
f[0][0]=0;
string::iterator iter=gen1.begin();
for(int i=1;i<=len1;i++){
//计算f[0][i]
int tmp_index=getIndex(*iter);
f[0][i]=f[0][i-1]+score_matrix[4][tmp_index];
iter++;
}
iter=gen0.begin();
for(int i=1;i<=len0;i++){
//计算f[i][0]
int tmp_index=getIndex(*iter);
f[i][0]=f[i-1][0]+score_matrix[4][tmp_index];
iter++;
}
}
int getIndex(char ch){
switch(ch){
case 'A':return 0;
case 'C':return 1;
case 'G':return 2;
case 'T':return 3;
default:return 4;
}
}