ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

填坑行动2-字符串DP

2021-02-15 21:35:54  阅读:194  来源: 互联网

标签:DNA 核苷酸 int s2 填坑 maxn 字符串 operatorname DP


目录
这是填坑行动的第二篇-字符串DP。

板子题

洛谷题目传送门

题目描述

\(\operatorname{DNA}\)分子是人类遗传信息的载体,它间接地指导蛋白质的合成。\(\operatorname{DNA}\)分子是由四种核苷酸组成的长链,这四种核苷酸分别是腺嘌呤核苷酸(用 \(\operatorname{A}\)代表)、鸟嘌呤核苷酸(用 \(\operatorname{G}\)代表)、胞嘧啶核苷酸(用 \(\operatorname{C}\)代表)和胸腺嘧啶核苷酸(用\(\operatorname{T}\)代表)。习惯上用一个字符集为 \(\{ \operatorname{{A,T,C,G}} \}\) 的字符串来表示一个\(\operatorname{DNA}\)分子序列,如 \(\operatorname{CGTTAGA}\)。

在生物进化过程中, \(\operatorname{DNA}\)分子可能发生各种各样的突变。这种突变形成了生物遗传信息的改变,从而使生物得以分化,构成了生物的多样性。
主要的突变有三种:
在一个 \(\operatorname{DNA}\)序列中插入一个新的核苷酸,
\(\operatorname{DNA}\)序列中丢失了一个核苷酸,
\(\operatorname{DNA}\)序列中的某个核苷酸被另一个核苷酸所取代。
所谓两个\(\operatorname{DNA}\)序列的一个比对是寻找一种排列方式,使得两个 \(\operatorname{DNA}\)序列在同样的位置上有相同的核苷酸,而若在同样的位置上两个DNA序列的核苷酸不同,则是由三种突变之一得到。例如,对两个\(\operatorname{DNA}\)序列\(T_1=\operatorname{ATCAG}\) \(T_2 =\operatorname{ACTAG}2\),可以按如下方式比对,(\(-\) 表示空白)
比对一:

\(T_1\) \(T_2\)
\(A\) \(A\)
\(T\) \(-\)
\(C\) \(C\)
\(A\) \(A\)
\(-\) \(T\)
\(T\) \(T\)

也可以按如下方式比对
比对二:

\(T_1\) \(T_2\)
\(A\) \(A\)
\(T\) \(C\)
\(C\) \(A\)
\(A\) \(T\)
\(T\) \(T\)

如果两个 \(\operatorname{DNA}\)序列在相同的位置上有越多相同的核苷酸对,则表明它们之间越相似,即它们存在功能上的相似性和进化史上的亲缘关系。
对于两个\(\operatorname{DNA}\)序列的一个比对,规定如下得分方式:
一个同样的位置上有相同的核苷酸对,则可得 \(1\)分;
一个同样的位置上有不同的核苷酸对,则得\(0\)分;
如果在某个位置上一个序列有核苷酸,而另一个序列在该位置上为\(-\),则得\(-2\) 分。例如,比对一的得分是\(0\)分,比对二的得分是\(3\)分。
问题是:对于两个\(\operatorname{DNA}\)序列,寻找一种比对方式,使得它们的得分最高。

输入格式

输入数据由文件名为INPUT.*的文本文件提供,共有2行。
第1行为DNA序列T1 , 第2行为DNA序列T2 。序列的长度不大于1000。序列中的字母是英文小写或者大写字母。

输出格式

程序运行结束时,在屏幕上输出所找出的最大的得分

输入输出样例

输入#1

Atcag
Actag

输入#2

3

算法理解

DP,说实话是普及组的一个坎,我们可以简单叙述一下DP的本质。
一、区间DP
我们可以用\(f_{i,j}\)来表示区间\(\left[ i,j \right]\)的答案,然后我们就可以根据题意,用\(f_{i-1,j},f_{i,j-1},f_{i-1,j-1}\)之类的来进行类推,有些时候我们甚至会用到\(3\)维甚至\(3\)维以上的数组,当然可以滚动,但是这里就不说了。
二、线性DP
我们可以用\(f_i\)可以表示区间\(\left[ 1,i \right]\)的答案,然后我们可以根据题意,用\(f_{i-1},f_{i-2}\)之类的来进行递推。
三、背包DP
待填坑
四、字符串背包
就是放在字符串上而已罢了。
敲重点,DP的精髓就在于方程式转移和背包DP!!!

题目解析

既然是DP题,那么我们就开始推DP式吧。
令\(f_{i,j}\)表示第一个字符串长度为\(i\),第二个字符串长度为\(j\)的时候,答案是多少。
那么,如果\(s1_i=s2_j\)的时候,我们就可以得出\(f_{i,j}=f_{i-1,j-1}+1\)
当然,我们也可以推出另外两个方程转移式:
\(f_{i,j}=f_{i-1,j}-2\)
\(f_{i,j}=f_{i,j-1}-2\)
综合可得:

\[f_{i,j}=\operatorname{max} \begin{cases} f_{i,j}+1& s1_i=s2_j\\ f_{i-1,j}-2\\ f_{i,j-1}-2 \end{cases}\]

以下为一堆代码、代码改进思路。
因为太蒟了所以会有一些没什么用的东西
长代码警告。

#include<cstdio>
#include<cstring>
#include<iostream>
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 1039
using namespace std;
char s1[maxn],s2[maxn];
int f[maxn][maxn];
int n1,n2;
int i,j,k;
int maxx;
int main(){
    cin>>s1>>s2;
    n1=strlen(s1); n2=strlen(s2); 
    for(i=0;i<n1;i++)
        if(s1[i]<'a')
            s1[i]+=32;
    for(i=0;i<n2;i++)
        if(s2[i]<'a')
            s2[i]+=32;
    if(s1[0]==s2[0])
        f[0][0]=1;	
    else f[0][0]=0;
    for(i=0;i<n1;i++)
        for(j=0;j<n2;j++){
        	if(i==j&&i==0) continue;
			maxx=f[i-1][j-1];//赋初值
        	if(s1[i]==s2[j])//条件
			    maxx=max(f[i-1][j-1]+1,maxx);//前一个满足条件就+1
			if(s1[i-1]==s2[j])//条件
			    maxx=max(f[i-1][j]-2,maxx);//空白-2
			if(s1[i]==s2[j-1])
			    maxx=max(f[i][j-1]-2,maxx);//空白-2
			f[i][j]=maxx;
		}
	printf("%d",f[n1-1][n2-1]);
	return 0;
}

结果:在这里插入图片描述
仅仅过了样例......
我们来分析一下,如果是空白的,其实是不需要条件的,所以我们改一下代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 1039
using namespace std;
char s1[maxn],s2[maxn];
int f[maxn][maxn];
int n1,n2;
int i,j,k;
int maxx;
int main(){
    cin>>s1>>s2;
    n1=strlen(s1); n2=strlen(s2); 
    for(i=0;i<n1;i++)
        if(s1[i]<'a')
            s1[i]+=32;
    for(i=0;i<n2;i++)
        if(s2[i]<'a')
            s2[i]+=32;
    f[0][0]=0;
    for(i=1;i<n1;i++)
        f[i][0]=f[i-1][0]-2;
    for(i=1;i<n2;i++)
        f[0][i]=f[0][i-1]-2;
    for(i=1;i<n1;i++)
        for(j=1;j<n2;j++){
			maxx=f[i-1][j-1];
        	if(s1[i]==s2[j]) maxx=max(f[i-1][j-1]+1,maxx);
			//if(s1[i-1]==s2[j])
			maxx=max(f[i-1][j]-2,maxx);
			//if(s1[i]==s2[j-1])
			maxx=max(f[i][j-1]-2,maxx);
			f[i][j]=maxx;
		}
	printf("%d",f[n1-1][n2-1]);
	return 0;
}

但是依然没有AC:
在这里插入图片描述
我们尝试自己造一组数据:
输入:

abc
abd

输出:

1

我们会发现循环的范围出现了问题。
我们把循环改成这样的:

for(i=1;i<=n1;i++)
    for(j=1;j<=n2;j++)

然后把if语句的地方改一改:if(s1[i-1]==s2[j-1])
然后就可以AC了。

#include<cstdio>
#include<cstring>
#include<iostream>
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 1039
using namespace std;
char s1[maxn],s2[maxn];
int f[maxn][maxn];
int n1,n2;
int i,j,k,flag;
int maxx;
int main(){
    cin>>s1>>s2;
    n1=strlen(s1); n2=strlen(s2); 
    for(i=0;i<n1;i++)
        if(s1[i]<'a')
            s1[i]+=32;
    for(i=0;i<n2;i++)
        if(s2[i]<'a')
            s2[i]+=32;
    f[0][0]=0;
    for(i=1;i<n1;i++)
        f[i][0]=f[i-1][0]-2;
    for(i=1;i<n2;i++)
        f[0][i]=f[0][i-1]-2;
    for(i=1;i<=n1;i++)
        for(j=1;j<=n2;j++){
        	flag=0;
        	if(s1[i-1]==s2[j-1])
        	    flag=1;
			f[i][j]=max(f[i-1][j-1]+flag,max(f[i-1][j]-2,f[i][j-1]-2));
		}
	printf("%d",f[n1][n2]);
	return 0;
}

标签:DNA,核苷酸,int,s2,填坑,maxn,字符串,operatorname,DP
来源: https://www.cnblogs.com/jiangtaizhe001/p/14405451.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有