C语言(CED)最长公共子序列----动态规划第一题

一、动态规划算法与分治法的异同

相同点

A、二者均是将待求解的问题分成若干子问题来求解。          

B、二者在编写代码的时候,都要用到递归

不同点

A、分治法求解的问题,在将问题分成若干子问题之后,其子问题之间是独立存在的,没有相互关联。而动态规划问题划分后得到的子问题之间相互关联。

B、动态规划问题在求解时需要一个表来记录已解决的子问题的答案,从而避免大量的重复计算。动态规划算法适合用于解最优化问题。这就表明这类最优化问题可能有很多解,但不一定都是最优解,而利用本算法找出的解可能还是众多最优解里的一个

二、最优解问题结构性质

最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

重叠子问题:在用递归算法自顶向下解决问题的时候,每次产生的子问题并不总是新问题,有些子问题被反复计算。动态规划算法正式利用这种子问题的重叠性质,对每个子问题只解一次,并将其保存在表格中。

从一般意义上来讲,问题所具有的这两个重要性质是该问题可用动态规划算法求解的基本要素。

三、动态规划问题分析及解决步骤

A、找出最优解的性质,刻画其结构特征。

B、递归定义最优值

C、自底向上计算最优值(最优值只是一个结果,最优解是一个过程)

D、根据得到的信息构造最优解(A-C是动态规划算法的进本步骤,此步在需要求出问题的最优解时才需执行)

好了,有了上面动态规划的基础知识后,我们开始本文的“重头戏”——最长公共子序列。

四、问题描述(问题大意)

子序列:一个给定序列中,删除若干元素后得到的序列,就是该序列的子序列。

公共子序列:如果有两个序列按照上述步骤之后得到的子序列相同,那么这个子序列被称为这两个序列的公共子序列。

例:有如下两个序列

X={A、B、C、B、D、A、B},Y={B、D、C、A、B、A}

则序列Z={B、C、A}就是二者的公共子序列,那么什么是最长的公共子序列,大家应该知道了吧?

在这里需要说明的是:一个长度为n的序列,它一共有2的n次方个子序列,有(2^n – 1)个非空子序列。大家需要注意的是,这里说的是序列,和原来的顺序有关联,而不是高中所学无序的集合。

下面将按照动态规划算法设计的步骤来设计解决此问题的算法

1、问题结构

 上述证明之后,本问题具有最优子结构性质。

2、递归结构

要找出X={x1,x2,...,xm}和Y={y1,y2,...,yn}的最长公共子序列,可按照以下方式递归:

A、当Xm=Yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上Xm(Xm=Yn),即可得X、Y的最长公共子序列。

B、当Xm!=Yn时,则得解决两个子问题:Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列,二者中较长者即为X和Y的最长公共子序列。

由这个递归结构来看,此问题具有子问题重叠性质,例如:在计算X和Y的最长公共子序列时,可能要计算X和Yn-1及Xm-1和Y的最长公共子序列,这两个子问题都包含一个公共子问题,即要计算Xm-1和Yn-1的最长公共子序列。

首先建立子问题最优值的递归关系,用从c[i][j]记录序列Xi和Yi的最长公共子序列的长度。其中,Xi={x1,x2,...,xi};Yj={y1,y2,...,yj}

当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,所以此时c[i][j]=0;

其他情况:

A、i>0;j=0时,c[i][j]=0;

B、i,j>0;Xi=Yj时,c[i][j]=c[i-1][j-1]+1

C、i,j>0;Xi!=Yj时,c[i][j]=max{c[i][j-1],c[i-1][j]}

3、计算最优值

直接利用上述递归式,写出代码。其中X,Y是输入的两个序列, ,b[i][j]记录c[i][j]的值是由哪个子问题的解得来的,这在构造最长公共子序列时要用到。

void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{int i,j;for(i=1;i<=m;i++)//当j=0时,c[i][j]=0c[i][0]=0;for(j=1;j<=n;j++)//当i=0时,c[i][j]=0c[0][j]=0;for(i=1;i<=m;i++)//对最长公共子序列的长度进行记录for(j=1;j<=n;j++){if(x[i]==y[j])//Xi=Yj的情况{c[i][j]=c[i-1][j-1]+1;//c[i][j]存储Xi和Yj的最长公共子序列的长度b[i][j]=1; //斜向上           //b[i][j]记录c[i][j]的值是由哪个子问题的解得来的}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;//竖直向上}else{c[i][j]=c[i][j-1];b[i][j]=3;//水平向左}}
}

4、构造最长公共子序列

用二维数组b快速构造序列X和Y的最长公共子序列。首先从b[m][n]开始,依照其值在数组b中搜索。

A、当在b[i][j]=1时,表示Xi和Yi的最长公共子序列是由Xi-1和Yi-1的最长公共子序列在尾部加上Xi所得到的。

B、当在b[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。

C、当在b[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。

如此,将最长公共子序列打印出来。代码如下:

void LCS(int i,int j,char x[], int b[][50])
{if(i==0||j==0)return;if(b[i][j]==1)//表示Xi和Yi的最长公共子序列是由Xi-1和Yi-1的最长公共子序列在尾部加上Xi所得到的{//b[i][j]==1时,表示左斜45°向上,也即这个时候对应的字母时LCS中的一个。LCS(i-1,j-1,x,b);cout<<x[i]<<" ";}else if(b[i][j]==2)//表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。LCS(i-1,j,x,b);else//表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。LCS(i,j-1,x,b);
}

所以,上述的所有步骤转变为完整代码如下:

#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;
int c[50][50];
int b[50][50];
char x[1000];//存放X字符串
char y[1000];//存放Y字符串
void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{int i,j;for(i=1;i<=m;i++)//当j=0时,c[i][j]=0c[i][0]=0;for(j=1;j<=n;j++)//当i=0时,c[i][j]=0c[0][j]=0;for(i=1;i<=m;i++)//对最长公共子序列的长度进行记录for(j=1;j<=n;j++){if(x[i]==y[j])//Xi=Yj的情况{c[i][j]=c[i-1][j-1]+1;//c[i][j]存储Xi和Yj的最长公共子序列的长度b[i][j]=1; //斜向上           //b[i][j]记录c[i][j]的值是由哪个子问题的解得来的}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;//竖直向上}else{c[i][j]=c[i][j-1];b[i][j]=3;//水平向左}}
}
void LCS(int i,int j,char x[], int b[][50])
{if(i==0||j==0)return;if(b[i][j]==1)//表示Xi和Yi的最长公共子序列是由Xi-1和Yi-1的最长公共子序列在尾部加上Xi所得到的{//b[i][j]==1时,表示左斜45°向上,也即这个时候对应的字母时LCS中的一个。LCS(i-1,j-1,x,b);cout<<x[i]<<" ";}else if(b[i][j]==2)//表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。LCS(i-1,j,x,b);else//表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。LCS(i,j-1,x,b);
}
int main()
{int xn,yn;//XY字符串的大小cout<<"请输入X集合的元素个数:"<<endl;cin>>xn;cout<<"请输入X集合的元素:"<<endl;int i=0;//用于循环输入X和Y的字符串for(i=1;i<=xn;i++)cin>>x[i];cout<<"请输入y集合的元素个数:"<<endl;cin>>yn;cout<<"请输入y集合的元素:"<<endl;for(i=1;i<=yn;i++)cin>>y[i];LCSLength(xn,yn,x,y,c,b);cout << "X和Y的最长公共子序列为:";LCS(xn,yn,x,b);cout << endl;int j = 0;int m = 0;printf("b[i][j]中的数字:\n");for (i = 0; i <=xn; i++)for (j = 0; j <= yn; j++){ printf("%d ", b[i][j]);m++;if (m == xn){m = 0;printf("\n");}}m = 0;printf("c[i][j]中的数字:\n");for (i = 0; i <= xn; i++)for (j = 0; j <=yn; j++){printf("%d ", c[i][j]);m++;if (m == xn){printf("\n");m = 0;}}	system("pause");return 0;
}

把c[i][j]和b[i][j]对应起来之后,得到下图:

从下图中可以看出,用二维数组b[i][j]中的信息可以构建出X和Y的一个最长公共子序列。从b[xn][yn]开始,沿着橘黄色的箭头方向追踪:

A、b[i][j]等于1时,左斜45°向上跳,并且起跳的字母就是LCS的一个成员

B、b[i][j]等于2时,竖直向上跳。

C、b[i][j]等于3时,水平向左跳。

参考:《计算机算法设计与分析·第五版 》王晓东编著

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言(CED)01背包——动态规划第二题

一、问题描述 给定n种物品和一个背包。物品i的质量Wi&#xff0c;其价值Vi&#xff0c;背包的容量为c。问如何选择装入背包中的物品&#xff0c;使得装入背包中的物品总价值最大&#xff1f; 二、解题思想 01背包和最长公共子序列都是动态规划题目中求最优解的问题&#xff0…

C语言(CED)gameboy接馅饼问题

一、题目大意 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。这馅饼别处都不掉&#xff0c;就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了&#xff0c;所以gameboy马上卸下身上的背包去接。但由…

C语言(CED)递归实现汉诺塔问题

一、问题大意 大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定&#xff0c;任何时候&#xff0c;在小圆盘上都不能放大圆盘&#xff0c;…

C语言(CED)智力大冲浪——贪心算法第一题

一、题目大意 小伟报名参加中央电视台的智力大冲浪节目&#xff0c;本次挑战赛吸引了众多参赛者&#xff0c;主持人为了表彰大家的勇气&#xff0c;先奖励每个参赛者m元。先不要太高兴&#xff01;因为这些钱还不一定都是你的&#xff01;接下来主持人宣布了比赛规则&#xff…

C语言(CED)钢条最优切割收益

目录 一、题目大意 二、大致思路 三、具体实现 一、题目大意 一家公司购买长钢条&#xff0c;将其切割成短钢条出售&#xff0c;切割本身没有成本&#xff0c;长度为i的短钢条的价格为Pi。那给定一段长度为n的钢条和一个价格表Pi,求钢条的切割方案使得收益Rn最大。提示&…

撰写paper时,如何在word里输入图片或其他文献(PDF)里的公式?(更新时间2022.03.01)

我们在写paper时&#xff0c;经常会遇到在Word里编写数学公式的问题&#xff0c;其中大多数公式是已经存在的&#xff0c;所以只需要识别、复制、粘贴即可&#xff0c;那么接下来&#xff0c;我就介绍一下“Mathtype”“Mathpix”的方法&#xff0c;分为所需软件、软件操作、公…

家里接入某运营商300M宽带,为何网速还是很慢?(还未装修房屋的请进来)

&#xff08;请先看置顶博文&#xff09;本博打开方式&#xff0c;请详读_liO_Oil的博客-CSDN博客_怎么把androidstudio卸载干净 引言&#xff1a;家里接入300M的宽带&#xff0c;但是自我感觉网速不佳&#xff0c;遂结合所学知识&#xff0c;对此问题进行分析、研究和调察&…

(CED)列指针与行指针的联系与区别

一、列指针&#xff08;竖为列&#xff09; 1、列指针相关定义 列指针&#xff1a;被称为是指针变量指向二维数组的某个元素 一般使用时会有如下定义&#xff1a; int a[3][4]{1,2,3,4,5,6,7,8,9,10,11,12}; int *p;而上述代码定义的指针p&#xff0c;一般按照下表方式指向…

一、Pytho第一课——Python安装及配置路径方法(最详细小白教程,没有之一。如若不懂,不是还可以私信嘛!对吧?)

目录 一、下载软件 二、安装 三、编辑器 四、在Pycharm上成功运行Python程序&#xff08;配置Python解释器&#xff09; 一、下载软件 官方下载地址&#xff1a;https://www.python.org/downloads/&#xff08;打开似乎很吃力&#xff0c;必要时刻“挂灯”&#xff09; …

二、Python第二课——变量命名规则及字符串变量相关函数

目录 一、变量命名规则 二、字符串变量及相关函数 1、字符串变量 2、相关函数 最后琐碎杂物&#xff1a; 1、字符串之间的拼接 2、字符串格式控制&#xff08;制表符和换行&#xff09; 一、变量命名规则 正如其他编程语言一样&#xff0c;程序离不开声明变量&#x…

三、Python第三课——Python中数字的用法及编码原则(Python禅意)

目录 一、Python中的数字 1、整数 2、浮点数 3、整数、浮点数和字符串的联系和区别 二、编码原则 1、为代码增加注释 2、Python 禅意 A、编码精美 B、避繁就简 C、无简就繁 D、使用常规方法解决问题 E、先有效、再精巧、逐步升华 一、Python中的数字 编程中&#…

四、Python第四课——Python中列表及其操作(增删改查)

目录 一、Python中的列表 1、列表的定义和赋值 2、列表的使用 二、列表的“增删改查” 1、列表中元素的增加 A、在列表尾添加元素 B、在列表中插入元素 2、列表中“元素的删除” A、使用del语句删除元素 B、使用pop()函数删除元素 C、弹出列表中任何位置元素…

五、Python第五课——Python中组织列表的相关函数

目录 一、用sort()函数对列表进行永久排序 二、用sorted()函数对列表进行临时排序 三、用reverse()函数对列表进行列表原始排序的逆序输出 四、使用len()函数确定列表长度 创建列表后&#xff0c;内部的元素逐渐增多&#xff0c;其排列顺序也是无法预测的&#xff0c;因为…

如何正确下载、安装Codeblocks?

目录 一、Codeblocks的下载 二、Codeblocks的安装 三、Codeblocks的运行 相信很多同学在初学C语言时都会选择一个短小精悍的代码编辑器&#xff0c;如CodeBlocks&#xff08;不说别的了&#xff0c;直接切入正题&#xff09;。 在2020年&#xff08;今年&#xff09;3月份-…

Python:创建列表,其中包含数字1-1000000,为什么Pycharm控制台结果显示不完整?

目录 一、问题描述&#xff08;寻找解决方法的同学直接看“标题二”&#xff09; 二、解决办法 一、问题描述&#xff08;寻找解决方法的同学直接看“标题二”&#xff09; 在学习Python过程中遇到一个这样的问题&#xff0c;也算是一个小BUG吧。题目大意是这样的&#xff…

六、Python第六课——Python中的for循环及数字列表

目录 一、Python中的for循环 1、for循环语句的声明。 2、for循环缩进常见问题 二、数字列表 1、函数range() 2、使用range()函数创建数字列表 3、使用一系列函数处理数字列表&#xff08;统计&#xff09; 4、列表解析&#xff08;生成列表的简洁方法&#xff09; 一…

七、Python第七课——有关列表的二三事(切片、切片的遍历和复制)

目录 一、切片 二、遍历切片 三、列表的复制 一、切片 此前&#xff0c;我们学习了如何访问单个列表以及如何处理列表中的所有元素&#xff0c;那么我们如何处理列表中的部分元素呢&#xff1f;这就引出一个概念“切片” 。我们可以把列表看成是面包&#xff0c;“切片”…

八、Python第八课——元组与列表、代码格式

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 一、元组的定义 二、元组的遍历 三、代码格式 一、元组的定义 1、元组&#xff1a;不可变的列表称为元组。这个是相对于普通列表而言的&#xff0c;普通列表…

九、Python第九课——Python中的if语句与运用

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 一、if语句 1、检查变量存储的值是否相等 2、判定字母或字符串时区别大小写 3、检查多个条件 4、检查特定值是否在列表中 二、if-else语句和if-elif-el…

十、Python第十课——字典的些许知识(重点)

&#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目录 &#xff08;请先看置顶博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 初识字典 1、创建字典 2、字典的“增删改查” …