填坑行动2-字符串DP
这是填坑行动的第二篇-字符串DP。
板子题
题目描述
分子是人类遗传信息的载体,它间接地指导蛋白质的合成。分子是由四种核苷酸组成的长链,这四种核苷酸分别是腺嘌呤核苷酸(用 代表)、鸟嘌呤核苷酸(用 代表)、胞嘧啶核苷酸(用 代表)和胸腺嘧啶核苷酸(用代表)。习惯上用一个字符集为 的字符串来表示一个分子序列,如 。
在生物进化过程中, 分子可能发生各种各样的突变。这种突变形成了生物遗传信息的改变,从而使生物得以分化,构成了生物的多样性。
主要的突变有三种:
在一个 序列中插入一个新的核苷酸,
序列中丢失了一个核苷酸,
序列中的某个核苷酸被另一个核苷酸所取代。
所谓两个序列的一个比对是寻找一种排列方式,使得两个 序列在同样的位置上有相同的核苷酸,而若在同样的位置上两个DNA序列的核苷酸不同,则是由三种突变之一得到。例如,对两个序列 ,可以按如下方式比对,( 表示空白)
比对一:
也可以按如下方式比对 | |
比对二: | |
-- | -- |
如果两个 序列在相同的位置上有越多相同的核苷酸对,则表明它们之间越相似,即它们存在功能上的相似性和进化史上的亲缘关系。 | |
对于两个序列的一个比对,规定如下得分方式: | |
一个同样的位置上有相同的核苷酸对,则可得 分; | |
一个同样的位置上有不同的核苷酸对,则得分; | |
如果在某个位置上一个序列有核苷酸,而另一个序列在该位置上为,则得 分。例如,比对一的得分是分,比对二的得分是分。 | |
问题是:对于两个序列,寻找一种比对方式,使得它们的得分最高。 |
输入格式
输入数据由文件名为INPUT.*的文本文件提供,共有2行。
第1行为DNA序列T1 , 第2行为DNA序列T2 。序列的长度不大于1000。序列中的字母是英文小写或者大写字母。
输出格式
程序运行结束时,在屏幕上输出所找出的最大的得分
输入输出样例
输入#1
Atcag Actag
输入#2
3
算法理解
DP,说实话是普及组的一个坎,我们可以简单叙述一下DP的本质。
一、区间DP
我们可以用来表示区间的答案,然后我们就可以根据题意,用之类的来进行类推,有些时候我们甚至会用到维甚至维以上的数组,当然可以滚动,但是这里就不说了。
二、线性DP
我们可以用可以表示区间的答案,然后我们可以根据题意,用之类的来进行递推。
三、背包DP
待填坑
四、字符串背包
就是放在字符串上而已罢了。
敲重点,DP的精髓就在于方程式转移和背包DP!!!
题目解析
既然是DP题,那么我们就开始推DP式吧。
令表示第一个字符串长度为,第二个字符串长度为的时候,答案是多少。
那么,如果的时候,我们就可以得出
当然,我们也可以推出另外两个方程转移式:
综合可得:
以下为一堆代码、代码改进思路。
因为太蒟了所以会有一些没什么用的东西
长代码警告。
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具