题目大意
- 题目给出一张5*5的映射表,分别是ACGT-,每对字符都有一个相似值。
- 给出两个字符串,由ACGT组成,求两个字符串匹配的最大相似值和,可以用-代替字符匹配。
分析
- 类似求最长公共子序列
- dp[i][j]表示s1中1….i和s2中的1….j匹配的最大相似值
状态转移方程
dp[i][j] = max{dp[i-1][j-1]+mp[a][b] , dp[i-1][j]+mp[a][4] , dp[i][j-1] + mp[4][b]}
记得初始化 dp[0][i] 和dp[i][0]
代码
#include <iostream>
#include <cstring>
using namespace std;
int mp[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}
};
const int maxn = 110;
int dp[maxn][maxn] = {{0} , {0}}; //dp[i][j]表示1..i匹配1..j时的最大相似值
int idx(char c)
{
switch(c) {
case 'A': return 0;
case 'C': return 1;
case 'G': return 2;
case 'T': return 3;
}
return 4;
}
//dp[i][j] = max{dp[i-1][j-1]+mp[a][b] , dp[i-1][j]+mp[a][4] , dp[i][j-1] + mp[4][b]}
int main()
{
int t; cin >> t;
while(t--)
{
int len1 , len2;
char s1[maxn] , s2[maxn];
cin >> len1;
for(int i = 1; i <= len1; i++) cin >> s1[i];
cin >> len2;
for(int i = 1; i <= len2; i++) cin >> s2[i];
for(int i = 1; i <= len2; i++) {
int k = idx(s2[i]);
dp[0][i] = dp[0][i-1] + mp[4][k];
}
for(int i = 1; i <= len1; i++) {
int k = idx(s1[i]);
dp[i][0] = dp[i-1][0] + mp[k][4];
}
for(int i = 1; i <= len1; i++) for(int j = 1; j <= len2; j++) {
int a = idx(s1[i]) , b = idx(s2[j]);
dp[i][j] = dp[i-1][j-1] + mp[a][b];
dp[i][j] = max(dp[i][j] , dp[i-1][j] + mp[a][4]);
dp[i][j] = max(dp[i][j] , dp[i][j-1] + mp[4][b]);
}
cout << dp[len1][len2] << endl;
}
return 0;
}