序列比对之动态规划

序列比对

问题描述
输入:两个序列A和B,其长度分别为m和n
输出:A和B的一种比对形式,其满足惩罚函数f(A,B)值最小。
(1) 对A和B之间的每一个空隙匹配,计惩罚分2分;
(2)对A和B之间的每一个错配,计惩罚分3分;
(3)成功配对不计惩罚分
最后求解得到最小的罚分值:

问题分析
1、分析问题的最优子结构性质
假设两个序列S1和S2,求他们的最长公共子序列,则:
1)S1[i] = S2[j],那么这两个数匹配
2)S1[i] != S2[j],S1[i-1] = S2[j],那么S1[i]匹配空
3)S1[i] != S2[j],S1[i] = S2[j-1],那么S2[j]匹配空
也就是说,当有相邻两个数据相等的时候,优先选择匹配相等的数据,将一个置空

2、建立递推公式
dp[i][j] 表示:S1的前 i 个字符和S2的前 j 个字符的匹配最小结果
1)dp[i][0] == 2i,此时都是空隙匹配
2)dp[0][j] == 2
j,此时都是空隙匹配
3)每次循环S1[i]与S2[j]匹配
如果相等那么不变dp[i][j]=dp[i-1][j-1]
如果不相等:dp[i][j]=min(dp[i-1][j-1]+3,dp[i-1][j]+2,dp[i][j-1]+2)

3、自底向上求解

4、根据计算最优值得到的信息,构造最优解

代码演示

#include <iostream>
using namespace std;

const int N=100;
string s1="aabcdefgaa";
string s2="abcdefglll";
int dp[N][N];
int main()
{
    /*
       a a b c d e f g a a _
       _ a b c d e f g l l l
    */

    int n=s1.size(),m=s2.size();//n行m列
    for(int i=0;i<=m;i++){
        dp[0][i]=2*i;
    }
    for(int i=0;i<=n;i++){
        dp[i][0]=2*i;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s1[i-1]==s2[j-1])
                dp[i][j]=min(min(dp[i-1][j-1],dp[i-1][j]+2),dp[i][j-1]+2);
            else
                dp[i][j]=min(min(dp[i-1][j-1]+3,dp[i-1][j]+2),dp[i][j-1]+2);
        }
    }

    cout<<"min="<<dp[n][m]<<endl;
    return 0;
}

posted @ 2020-12-18 17:17  快要学不动了  阅读(542)  评论(0)    收藏  举报