洛谷P1140 相似基因(线性DP)

题意:

给出两个给定长度的基因串,然后给出各个碱基之间匹配的相似度,碱基也可以与空碱基配对,问这两串基因匹配的最大相似度。

做法:

首先是自己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;
}

猜你喜欢

转载自blog.csdn.net/qq_44607936/article/details/98775574