P1140 相似基因
链接:https://www.luogu.com.cn/problem/P1140
题目:
思路:设置递推状态:dp[i][j]表示a的前i个碱基和b的前j个碱基配对的最大值。
那么递推:
1.ans1设置为dp[i-1][j-1]+val[a[i]][b[j]]就是说a[i]和b[j]可以凑一对,那么就凑;
2.ans2设置为dp[i-1][j]+val[0][a[i]]就是说a[i]和b的空凑一对;
3.ans3设置为dp[i][j-1]+val[0][b[j]],即b[j]与a的空凑一对。
然后取ans= max(ans1,ans2,ans3)即可
比较好的blog:https://www.luogu.com/paste/u7l8dqnn
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
typedef long long ll;
using namespace std;
const int N = 110;
ll dp[N][N];
map<char, int>mp;
ll val[5][5]={
{INT_MIN,-3,-4,-2,-1},
{-3,5,-1,-2,-1},
{-4,-1,5,-3,-2},
{-2,-2,-3,5,-2},
{-1,-1,-2,-2,5}};
string a, b;
ll dfs(ll ik, ll jk)
{
if (!ik and !jk)return 0;
if (ik == 0)
{
ll res = 0;
for (int i = 0; i < jk; i++)res += val[0][mp[b[i]]];
return dp[0][jk] = res;
}
if (!jk)
{
ll res = 0;
for (int i = 0; i < ik; i++)res += val[0][mp[a[i]]];
return dp[ik][0] = res;
}
if (dp[ik][jk])return dp[ik][jk];
ll ans1 = dfs(ik-1,jk-1) + val[mp[a[ik - 1]]][mp[b[jk - 1]]];
ll ans2 = dfs(ik - 1, jk) + val[mp[a[ik - 1]]][0];
ll ans3 = dfs(ik, jk - 1) + val[mp[b[jk - 1]]][0];
ll ans = max(ans1, max(ans2, ans3));
return dp[ik][jk] = ans;
}
int main()
{
int na, nb;
cin >> na >> a >> nb >> b;
if (a.length() < b.length())swap(a, b);
//a.length()>=b.length()
//dp[i][j]:a[i],b[j]
mp['A'] = 1; mp['C'] = 2; mp['G'] = 3; mp['T'] = 4;
cout << dfs(a.length(), b.length());//其实换不换都没关系,是我脑子抽了()
return 0;
}