P1140 相似基因

考虑如何设计状态。

设给出的两个串为串 \(A\) 和串 \(B\),长度分别为 \(n\)\(m\)

我们用 \(f[i][j]\) 来表示前 \(i\)\(A\) 串碱基和前 \(j\)\(B\) 串碱基得到的最大相似度。

我们因为求的是最大的相似度,而从题目给的表来看是可能为负的,所以先初始化一下 \(f[i][j]\) 数组。

那么我们就考虑到有三种转移的方式:

  1. 当前 \(A\) 串插入一个空碱基。

  2. 当前 \(B\) 串插入一个空碱基。

  3. 当前串不插入空碱基,直接进行相似度比对。

两个串都插入空碱基相当于没插入,所以不考虑。

我们知道一个空串和碱基序列的相似度就是相当于碱基序列都是和空碱基进行相似度比对,所以我们要进行一个小小的预处理。

code:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
#define N 1010
using namespace std;
int n,m,f[N][N],a[N],b[N];
string s1,s2;
int mp[10][10]=
{
	{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},
};
inline void init(int len,string a,int b[])
{
	for(int i=1;i<=len;i++)
	{
		if(a[i-1]=='A')b[i]=0;
		if(a[i-1]=='C')b[i]=1;
		if(a[i-1]=='G')b[i]=2;
		if(a[i-1]=='T')b[i]=3;
	}
}
signed main()
{
	cin>>n>>s1>>m>>s2;
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
	    f[i][j]=-INF;//预处理
	init(n,s1,a);
	init(m,s2,b);
    for(int i=1;i<=n;i++)f[i][0]=f[i-1][0]+mp[a[i]][4];//预处理 
    for(int i=1;i<=m;i++)f[0][i]=f[0][i-1]+mp[b[i]][4];
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=m;j++)
    	{
    		f[i][j]=max(f[i][j],f[i-1][j]+mp[a[i]][4]);//A串插入空碱基 
    		f[i][j]=max(f[i][j],f[i][j-1]+mp[b[j]][4]);//B串插入空碱基 
    		f[i][j]=max(f[i][j],f[i-1][j-1]+mp[a[i]][b[j]]);//不插入空碱基 
		}
	}
	cout<<f[n][m]<<endl;
    return 0;
}

P1279 字串距离

一眼看去和上面那道题目一样,区别就是更好写了,因为加的值都能直接得出。

同样分三种情况转移。

code:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
#define N 2010
using namespace std;
string s1,s2;
int n,m,k,f[N][N],a[N],b[N];
signed main()
{
	cin>>s1>>s2>>k;
	n=s1.size();
	m=s2.size();
	for(int i=1;i<=n;i++)a[i]=s1[i-1]-'a';//字符转数字方便计算,同时把下标从0开始改为从1开始 
	for(int i=1;i<=m;i++)b[i]=s2[i-1]-'a';
	memset(f,INF,sizeof f);f[0][0]=0;//赋初值,f[0][0]特殊处理 
	for(int i=1;i<=n;i++)f[i][0]=f[i-1][0]+k;//预处理和空串匹配的距离 
	for(int i=1;i<=m;i++)f[0][i]=f[0][i-1]+k;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			f[i][j]=min(f[i][j],f[i-1][j]+k);//往j中插入空格 
			f[i][j]=min(f[i][j],f[i][j-1]+k);//往i中插入空格 
			f[i][j]=min(f[i][j],f[i-1][j-1]+abs(a[i]-b[j]));//不插入空格,直接计算两个字符的ascll码的差值 
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}