序列比对
问题描述
输入:两个序列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] == 2j,此时都是空隙匹配
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;
}