秒懂算法 | 汉诺塔问题与木棒三角形

news2024/11/24 6:01:28

图片

在数学与计算机科学中,递归(recursion)是指一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。递归的能力在于用有限的语句定义对象的无限集合。一个递归问题可分为递推和回归两个阶段。在递推阶段,把较复杂问题(规模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解;在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解。

只有同时满足下面三个条件的问题,才能用递归解决。

(1) 一个问题可以转化为一个与原问题相似的、规模较小的子问题来求解。比如,在n的阶乘的计算中,将n的阶乘的问题转化为n-1的阶乘乘以n,此问题便可解决。

(2) 这个问题与分解之后的子问题,除数据规模不同,求解思路完全一样。比如,n的阶乘问题中,求解n的阶乘的思路,和求解n-1的阶乘的思路是一模一样的。

(3) 存在递归终止条件。

把问题分解为子问题,再把子问题分解为子子问题,一层一层分解下去,不能存在无限循环,这就需要有终止条件。比如,n的阶乘问题中,0或1的阶乘为1,也就是f(1)=1,f(0)=1,这就是递归的终止条件。

递归是很多算法实现的基础,是程序设计中的一种重要思想和机制,如分治、深度优先搜索、动态规划等算法中均用到递归思想。

01、汉诺塔问题

汉诺(Hanoi)塔问题是一个经典的运用递归方法解决问题的例子。

问题描述:

汉诺塔是一个发源于印度的益智游戏,也叫河内塔。相传它源于印度神话中的大梵天创造的三根金刚柱,一根柱子上叠着上下从小到大64个黄金圆盘。大梵天命令婆罗门将这些圆盘按从小到大的顺序移动到另一根柱子上,其中大圆盘不能放在小圆盘上面。当这64个圆盘移动完的时候,世界就将毁灭。

那么,好多人会问64个圆盘移动到底会花多少时间?古代印度距离现在已经很远,这64个圆盘还没移动完么?我们通过计算看完成这个任务到底要多少时间?计算结果非常恐怖,移动圆盘的次数为2n-1,即18446744073709551615,假设移动一次圆盘用时一秒,一年为31536000秒。那么,18446744073709551615/31536000约等于584942417355年,即约为5850亿年。目前太阳寿命约为50亿年,太阳的完整寿命大约100亿年。所以,整个人类文明都等不到移动完整圆盘的那一天。很多人对汉诺塔的解法产生了兴趣。从一阶汉诺塔到N阶汉诺塔它们是否有规律性的算法?能否编程输出每一次移动的方法呢?这就是本例要解决的问题。

输入:

输入一个正整数n,表示有n个圆盘在第一根柱子上。

输出:

输出操作序列,格式为move t from x to y。每个操作一行,表示把x柱子上的编号为t的盘片挪到柱子y上。柱子编号为a,b,c,要用最少的操作把所有盘子从a柱子上转移到c柱子上。

输入样例:

3

输出样例:

move 1 from a to c
move 2 from a to b
move 1 from c to b
move 3 from a to c
move 1 from b to a
move 2 from b to c
move 1 from a to c

解题思路:

实现这个算法,可以简单分为以下三个步骤。

(1) 把第n-1个圆盘由a移到b。

(2) 把第n个圆盘由a移到c。

(3) 把第n-1个圆盘由b移到c。

从这里入手,加上上面数学问题解法的分析,不难发现,移动的步数必为奇数步。

(1) 第二步是把a柱子上剩下的一个盘子移到c柱子上。

(2) 第一步可以看成把a柱子上的n-1个圆盘借助c柱子移到b柱子上。

(3) 第三步可以看成把b上的n-1个圆盘借助a柱子移到c柱子上。

如3阶汉诺塔的移动: A→C,A→B,C→B,A→C,B→A,B→C,A→C。

参考程序:

#include <fstream>
#include <iostream>
using namespace std;
/ *将x柱子上编号为 t的圆盘移动到 柱子上 * /
void Move(int t,char x,char y) [cout<<"move "<<t<<" from "<<x<<" to "<<y<<endl;
/*将 n个圆盘从 a 柱子借助 b 柱子移到 c 柱子 * /
void Hannoi(int n,char a,char b,char c)
{
  if(n==1)
move(1,a,c)
Move(1,a,c); /* 若只有一个圆盘,则直接将该圆盘由 a 柱子移到 c 柱子 * /
else
{
Hannoi(n-1,a,c,b); / * 把 a 柱子上的 n-1个圆盘借助 c 柱子移到 b 柱子上* /
Move(n,a,c);  /*把 a 柱子上剩下的一个盘子移到 c 柱子上*/
Hannoi(n-1,b,a,c);  /*把b 柱子上的 n-1个圆盘借助 a 柱子移到 c 柱子上* /
 
}
})


int main()
int n;
scanf("%d",&n);
Hannoi(n,'a','b','c') ;
return 0;
}

02、木棒三角形

问题描述:

小A家里有很多长度不一的木棒,有一天他很无聊,摆弄这些木棒解闷。小A的数学学得很好,所以他想在这些木棒中挑出三根木棒组成一个直角三角形,当然,这可能有很多种选法,他还想挑出三根木棒组成一个面积最大的直角三角形。

输入:

输入有多组,每组输入包括两行,第一行输入一个n(0≤n≤100),表示小A有n根木棒,接着一行有n个整数(n≤1000),表示木棒的长度(长度从小到大给出)。

输出:

输出面积最大的直角三角形的面积,且保留3位小数,若不能组成,则输出“My Good!”。

输入数据:

4
1 2 3 4
5
2 3 4 5 6
6
3 4 5 6 8 10
2
1 1

输出数据:

My Good!
6.000
24.000
My Good!

解题思路:

看到题目很容易想到如果求出从n根木棒中选出三根木棒的所有情况的解,那答案也就出来了。

现在的主要问题是怎么用程序枚举所有情况。我们知道直角三角形的三条边中斜边是最长的,题目给出一个“长度从小到大给出”的条件,这样我们可以依次枚举三角形中长度最短、第二长和最长的边,具体实现代码如下。

参考程序:

#include< stdio.h>
#include<stdlib.h>
int main()
{
int i,j,k;
double ans;
int n;
int len[110];
while(scanf(rd",&n)!=EOF)
{for(i = 1;i <= n;i++)scanf("%d",&len[i]); //存储木棒长度
ans = -1;
for(i = l;i <= n;i++){  //枚举最短木棒
for(j = i+l;j <= n;j++){ //枚举第二长的木棒
for(k = j+1;k <= n;k++){  //枚举最长的木棒
if(len[i]*len[i] + len[j]*len[j] == len[k]* len[k]){ //如果是直角三角形
if(0.5*len[i]*len[j] > ans) //取最优解
ans = 0.5*len[i]*len[j];
}
}
}
}

if(ans == -1)
printf("My Good! \n");
else
printf("%.3lf\n",ans);
}

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

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

相关文章

JAVA权限管理 助力企业精细化运营

在企业的日常经营中&#xff0c;企业人数达到一定数量之后&#xff0c;就需要对企业的层级和部门进行细分&#xff0c;建立企业的树形组织架构。围绕着树形组织架构&#xff0c;企业能够将权限落实到个人&#xff0c;避免企业内部出现管理混乱等情况。权限管理是每个企业管理中…

【3Ds Max】弯曲命令的简单使用

简介 在3ds Max中&#xff0c;"弯曲"&#xff08;Bend&#xff09;是一种用于在平面或曲面上创建弯曲效果的建模命令。使用弯曲命令&#xff0c;您可以将对象沿特定轴向弯曲&#xff0c;从而创建出各种弯曲的几何形状。以下是使用3ds Max中的弯曲命令的基本步骤&…

多数据源项目serviceImpl中使用了@PostConstruct注解导致项目启动时报“表不存在”的解决办法

背景&#xff1a; 原多数据源项目一直运行好好的&#xff0c;这两天开发定时任务调度功能&#xff0c;开发完了调用定时任务一直提示找不到定时任务&#xff0c;调查半天发现没有提前把表中定义的定时任务加载到ScheduleJob&#xff0c;也就是需要执行以下操作&#xff1a; Pos…

获取屏幕共享视频流

文章目录 1.增加 html 的一行代码2. 在 static 目录下创建 js 文件夹&#xff0c;并在 js 文件夹下面创建 screen_share.js 文件3. 访问 htpps 的网址3.1 点击开始推流3.2 选择要分享的窗口3.3 停止推流 1.增加 html 的一行代码 <script src"/static/js/screen_share.…

不会吧,小红书竟然也偷用户作品训练自家AI模型?

图片来源&#xff1a;由无界AI生成 “画手在小红书发的图是可以随意被拿去炼的吗&#xff1f;” 最近一个月&#xff0c;有关“小红书偷用户作品炼自家AI模型”的话题不断发酵&#xff0c;用户在小红书以及其他社交平台发起抵制行动。一部分画师停止在小红书更新作品&#xff0…

安装nodejs

1.下载nodejs的压缩包 https://nodejs.org/download/release/latest-v16.x/ 这个是v16版本的&#xff0c;可以根据自己需求下载对应的版本&#xff1a; https://nodejs.org/download/release/ 2.解压&#xff0c;将nodejs放到固定的路径下 注意&#xff1a;不要包含中文路径 3.…

「隐语小课」拆分学习之“水平拆分学习”

一、引言 拆分学习是 2018 年由 MIT 最先提出的分布式算法。本文结合该领域的相关英文文献&#xff0c;介绍水平拆分学习的基本方法&#xff0c;同时还将对比拆分模型与中心化模型、联邦模型在不同条件下模型效率和准确性。拆分学习作为主流的隐私计算学习范式之一&#xff0c…

opencv 矩阵运算

1.矩阵乘&#xff08;*&#xff09; Mat mat1 Mat::ones(2,3,CV_32FC1);Mat mat2 Mat::ones(3,2,CV_32FC1);Mat mat3 mat1 * mat2; //矩阵乘 结果 2.元素乘法或者除法&#xff08;mul&#xff09; Mat m Mat::ones(2, 3, CV_32FC1);m.at<float>(0, 1) 3;m.at…

c语言——判断,判断是否是字母

//判断&#xff0c;判断是否是字母 #include<stdio.h> #include<stdlib.h> int main() {char c;printf("输入字符&#xff1a;");scanf("%c",&c);if((c>a&&c<z)||(c>A&&c<Z)) //a~z的ASCLL区间是97-122&…

【广州虚拟现实开发】VR智能中控系统进一步提高VR教学管理水平

随着科技的不断发展&#xff0c;虚拟现实(VR)技术已经逐渐走进了人们的生活。在教育领域&#xff0c;VR技术也得到了广泛的应用&#xff0c;尤其是在教学终端中控系统方面。那么&#xff0c;广州华锐互动开发的VR智能中控系统对学校有何益处呢&#xff1f; 首先&#xff0c;VR智…

【Nginx18】Nginx学习:WebDav文件存储与图片媒体处理模块

Nginx学习&#xff1a;WebDav文件存储与图片媒体处理模块 今天的内容怎么说呢&#xff1f;有两个感觉非常有意思&#xff0c;另外一些就差点意思。有意思的是&#xff0c;咱们可以直接用 Nginx 的 Webdav 功能搭建一个网盘&#xff0c;另外也可以实现动态的图片处理。这两个功能…

1AE4 的魔改混合放大电路

先上电路图&#xff1a; 最新的1AE4的电路&#xff0c;目标依旧是极致的音效。 因此&#xff0c;为了将1AE4的潜力榨干&#xff0c;采用了一些完全不同的思路&#xff1a; 1&#xff09;原有的屏极接地&#xff0c;因为是一个壳子&#xff0c;所以能起到很好的屏蔽作用&#…

图解算法--排序算法

目录 1.冒泡排序算法 2.选择排序算法 3.插入排序算法 4.希尔排序算法 5.归并排序算法 6.快速排序算法 1.冒泡排序算法 原理讲解&#xff1a; 从待排序的数组中的第一个元素开始&#xff0c;依次比较当前元素和它相邻的下一个元素的大小。如果当前元素大于相邻元素&#x…

7. 实现 API 自动生成

目录 1. pom.xml中引用依赖 2. 引入相关的依赖 3. 编写配置类 4. application.yml 中添加配置 5. API 常用注解 6. 访问 API 列表 7. API 导入 Postman 使用 Springfox Swagger生成 API&#xff0c;并导入 Postman&#xff0c;完成API单元测试。 Swagger 简介&#xff1a;Swag…

记录一个编译TubeTK时的报错:at_check问题

在使用如下命令安装TubeTK的cuda_nms时&#xff0c;报了一个错误&#xff0c;记录一下这个错误和解决办法 (base) redmeryredmery:~/Desktop/MOT/TubeTK/post_processing/nms$ python setup.py build_ext --inplace因为这个命令是在/home/redmery/Desktop/MOT/TubeTK/install/…

途乐证券-炒股开户流程是怎样的?

炒股是一种危险较大但收益也相对较高的出资方法&#xff0c;而开户则是出资炒股的前提。跟着科技的开展&#xff0c;炒股开户已经能够在线完结&#xff0c;但流程相对来说仍是比较繁琐的。那么&#xff0c;炒股开户流程是怎样的呢&#xff1f;下面从多个视点剖析。 一、炒股开户…

基于Servlet实现的管理系统(包含服务器源码+数据库)

资料下载链接 介绍 基于Servlet框架的管理系统 简洁版 &#xff1b; 实现 登录 、 注册 、 增 、 删 、 改 、 查 &#xff1b; 可继续完善增加前端、校验、其他功能等&#xff1b; 可作为 Servlet项目 开发练习基础模型&#xff1b; 课程设计 、 毕业设计 开发基础&…

PublicDNS服务提供商增加字节,将支持 DoH/DoT/DoQ 等协议

随着互联网的发展&#xff0c;网页的复杂程度也在增加。客户端在访问一个网页时&#xff0c;通常需要发送数十个 DNS 查询请求才能完整加载一个网页的全部资源。在这种情况下&#xff0c;DNS 解析的速度和准确率会影响网页的加载速度。 公共解析 PublicDNS 向用户提供 DNS 服务…

Android Studio导入项目需要做的一些配置

点击项目结构 选择本地安装的SDK、NDK目录 选择java版本 重新加载项目 Clean Project Rebuild Project 选择要构建的版本 可选debug和release 打包apk安装包 打包完成&#xff0c;就可以安装到安卓手机了

c语言——连接字符串

//连接字符串 #include<stdio.h> #include<stdlib.h> int main() {char s1[100],s2[100],i,j;printf("第一个字符串&#xff1a;");scanf("%s",s1);printf("第二个字符串&#xff1a;");scanf("%s",s2);for(i0;s1[i]!\0;i…