题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=27
类似于最长公共子序列。
用f[i][j]表示第一个基因序列s1的前i个字符和第二个基因序列s2的前j个字符对齐后的最大相似度,函数dis用来计算两个字符之间的相似度,分三种情况:
1.在s1的第i个字符后面插入空格与s2的第j个字符匹配,f[i][j] = f[i][j-1]+dis(s2[j],'-');
2.在s2的第j个字符后面插入空格与s1的第j个字符匹配,f[i][j] = f[i-1][j]+dis(s1[i],'-');
3.让s1的第i个字符与s2的第j个字符匹配,f[i][j] = f[i-1][j-1]+dis(s1[i],s2[j])。
注意考虑初始化:
for (int i=1; i<=n; i++)
f[i][0] = f[i-1][0] + dis(s1[i],'-');
for (int j=1; j<=m; j++)
f[0][j] = f[0][j-1] + dis(s2[j],'-');
#include<iostream> #include<cstdio> #include<memory.h> using namespace std; int f[110][110]; int d[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,-100}}; int dis(char c1, char c2) { int a, b; switch (c1) { case 'A':a = 0; break; case 'C':a = 1; break; case 'G':a = 2; break; case 'T':a = 3; break; case '-':a = 4; break; } switch (c2) { case 'A':b = 0; break; case 'C':b = 1; break; case 'G':b = 2; break; case 'T':b = 3; break; case '-':b = 4; break; } return d[a][b]; } int main() { int T; scanf("%d",&T); while (T--) { int n,m; char s1[110],s2[110]; scanf("%d%s",&n,&s1[1]); scanf("%d%s",&m,&s2[1]); memset(f,0,sizeof(0)); for (int i=1; i<=n; i++) f[i][0] = f[i-1][0] + dis(s1[i],'-'); for (int j=1; j<=m; j++) f[0][j] = f[0][j-1] + dis(s2[j],'-'); for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) { f[i][j] = max(max(f[i][j-1]+dis(s2[j],'-'), f[i-1][j]+dis(s1[i],'-')), f[i-1][j-1]+dis(s1[i],s2[j])); } cout<<f[n][m]<<endl; } return 0; }