题意:
给出两个给定长度的基因串,然后给出各个碱基之间匹配的相似度,碱基也可以与空碱基配对,问这两串基因匹配的最大相似度。
做法:
首先是自己yy了一个类似及其麻烦的做法,然后发现字符串的长度是不定的,不一定第一个基因串一定比第二个基因串长,错的一塌糊涂。下面是正解。
dp[i][j]表示前i个碱基与前j个碱基匹配的情况,只看它们匹配结果的结尾可以分为三种情况:
1.i与j匹配
2.i和空格匹配
3.j和空格匹配
所以每一个状态都可以由这三种情况得到,然后取最大的情况就行。个人觉得有种LCS的感觉。
然后要注意初始化前i个碱基与前0个碱基配对,这个状态的最大值就是前i个碱基与空碱基配对的值。要取最大值,其他的都赋值为负无穷即可。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=110;
char s1[maxn],s2[maxn];
int dp[maxn][maxn];
int tab[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}
};//列个表
map<char,int> maps;
int main()
{
int len1,len2;
scanf("%d%s",&len1,s1+1);
scanf("%d%s",&len2,s2+1);
maps['A']=0;maps['C']=1;maps['G']=2;maps['T']=3;maps['-']=4;
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++) dp[i][j]=-inf;
}
for(int i=1;i<=len1;i++) dp[i][0]=dp[i-1][0]+tab[maps[s1[i]]][4];
for(int i=1;i<=len2;i++) dp[0][i]=dp[0][i-1]+tab[maps[s2[i]]][4];
dp[0][0]=0;
/*相当于把问题分成了小的子问题,len1个与len2个匹配,分解为i和j个匹配,然后地推过去*/
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+tab[maps[s1[i]]][maps[s2[j]]]);
dp[i][j]=max(dp[i][j],dp[i-1][j]+tab[maps[s1[i]]][4]);
dp[i][j]=max(dp[i][j],dp[i][j-1]+tab[4][maps[s2[j]]]);
//printf("%d %d:%d\n",i,j,dp[i][j]);
}
}
printf("%d\n",dp[len1][len2]);
return 0;
}