思路:仍然是一道简单的DP,首先我们来分析一下有几种策略可以选择
1.令第一条链的碱基与空碱基配对
2.令第二条链的碱基与空碱基配对
3.令两条链的碱基相互配对
那么我们很容易就能够得到状态转移方程了,dp[i][j]表示第一条链的1~i部分与第二条链的1~j部分的最大匹配值
dp[i][j] = max{dp[i][j], dp[i-1][j]+a[i]与空碱基的匹配值, dp[i][j-1]+b[j]与空碱基的匹配值, dp[i-1][j-1]+a[i]与b[i]的匹配值}
因为i和j都要用到之前的状态,所以i和j都从1开始推
/** * 题目: 洛谷OJ: P1140 相似基因(DP) * 题型: DP **/ #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn = 100+10; const int w[6][6] = {{0,0,0,0,0,0}, {0,5,-1,-2,-1,-3}, {0,-1,5,-3,-2,-4}, {0,-2,-3,5,-2,-2}, {0,-1,-2,-2,5,-1}, {0,-3,-4,-2,-1,0}}; int dp[maxn][maxn], a[maxn], b[maxn], n, m; int create() { char ch; cin >> ch; switch(ch) { case 'A': return 1; case 'C': return 2; case 'G': return 3; case 'T': return 4; } } int main() { /************input**************/ cin >> n; for(int i = 1; i <= n; i++) a[i] = create(); cin >> m; for(int i = 1; i <= m; i++) b[i] = create(); /*******************************/ /************init***************/ //初始化工作一定要做好, 开始因为初始化疏忽大意WA了一个点 memset(dp, -0x3f, sizeof(dp)); dp[0][0] = 0; for(int i = 1; i <= n; i++) dp[i][0] = dp[i-1][0] + w[a[i]][5]; for(int i = 1; i <= m; i++) dp[0][i] = dp[0][i-1] + w[b[i]][5]; /*******************************/ for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { //为了方便阅读就不使用这种写法了 //dp[i][j] = max( dp[i][j], max( dp[i-1][j]+w[a[i]][5], max(dp[i][j-1]+w[b[j]][5], dp[i-1][j-1]+w[a[i]][b[j]]) ) ); dp[i][j] = max(dp[i][j], dp[i-1][j]+w[a[i]][5]); //令a[i]与空碱基配对 dp[i][j] = max(dp[i][j], dp[i][j-1]+w[b[j]][5]); //令b[j]与空碱基配对 dp[i][j] = max(dp[i][j], dp[i-1][j-1]+w[a[i]][b[j]]); //令a[i]与b[j]配对 } } cout << dp[n][m] << endl; return 0; }