王道机试C++第8章递归与分治 Day35和蓝桥杯两道真题程序

news2024/11/19 8:42:24

第 8 章 递归与分治

递归是指:函数直接或间接调用自身的一种方法,通常可把一个复杂的大型问题层层转化为与原问题相似但规模较小的问题来求解。
递归策略只需少量的程序就可描述解题过程所需的多次重复计算,因此大大减少了程序的代码量。

8.1 递归策略

构成递归需要具备两个条件:
1) 子问题必须与原始问题相同,且规模更小。
2) 不能无限制地调用本身,必须有一个递归出口。

例:n 的阶乘

题目描述:
输入一个整数 n ,输出 n 的阶乘(每组测试用例可能包含多组数据,请注意处理)。
输入: 一个整数 n 1 <=   n <=   20
输出: n 的阶乘
样例输入:
3
样例输出:
6
递归问题思路:
代码表示:
#include <bits/stdc++.h>
using namespace std;

int Factorial(int n){
	if(n==1){
		return 1;
	}
	else{
	return Factorial(n-1)*n;
    }
}
int main() {
    int n;
    scanf("%d",&n);
    printf("%d\n", Factorial(n));
    return 0;
}

例:汉诺塔 III

题目描述:
在一块铜板上有三根杆,最左边的杆自上而下、由小到大顺序串着由 64 个圆盘构成的塔。目的是将最左边杆上的圆盘全部移到右边的杆上条件是一次只能移动一个圆盘,并且不允许大圆盘放在小圆盘的上面。
现在我们改变这个游戏的玩法:不允许直接从最左(右)边移动到最右(左)边(每次移动一定是移到中间杆或从中间杆移出),也不允许大圆盘放到小圆盘的上面。 现在有 N 个圆盘,她至少需要多少次移动才能把这些圆盘从最左边移到最右边?
输入: 包含多组数据,每次输入一个 N 值( 1 <=   N <=  35 )。
输出: 对于每组数据,输出移动最小的次数。
样例输入:
1
3
12
样例输出:
2
26
531440
代码表示:
#include <bits/stdc++.h>
using namespace std;
long long hanoi(int n){
	if(n==1){
		return 2;
	}
	else{
	return 3*hanoi(n-1)+2;
    }
}
int main() {
    int n;
    while (scanf("%d",&n)!=EOF){
    	printf("%lld",hanoi(n));
	}
    return 0;
}

思路提示:

       若从第一根杆上移动 N 个圆盘到第三根杆上需要 F[N] 次移动,那么综上所述 F[N] 的组成方式 如下:先移动 N -1个圆盘到第三根杆上需要 F[N -1] 次移动,然后将最大的圆盘移动到中间杆上需要 1 次移动,再将 N -1个圆盘移动回第一根杆上同样需要 F[N-1] 次移动,移动最大的盘子到第三根杆上需要 1 次移动,最后将 N -1个圆盘移动到第三根杆上需要 F[N -1] 次移动,于是便有了 F[N] = 3F[N -1] + 2 。也就是说,从第一根杆上移动 N 个圆盘到第三根杆上,需要三次从第一根杆上移动 N -1个圆盘到第三根杆上,外加两次对最大圆盘的移动。这样就可以将移动 N 个圆盘的问题转换为问题相同但规模更小的移动 N -1个圆盘的问题。

        递归出口:当 N 1 时,即从第一根杆上移动一个盘子到第三根杆上,所需的移动次数显而易见为 2。移动一个盘子所需次数是最底层的子问题,该子问题不可继续分解且易于求解。这便是递归的出口。


8.2 分治法

分治法字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多个子问题,子问题之间互相独立且与原问题相同或相似。之后再把子问题分成更小的子问题,以此类推,直到最后的子问题可以简单地直接求解,原问题的解即子问题的解的合并。由于分治法产生的子问题往往与原问题相同且模式更小,这就为使用递归策略求解提供了条件。在这种情况下,通过反复利用分治手段,可以使子问题的规模不断缩小,最终缩小到可以直接求解的情况。在从过程中会导致了递归过程的产生。分治与递归就像一对孪生兄弟,经常同时应用在算法设计中,这也是将分治法和递归策略放在同一章中进行讲解的原因。分治法的步骤如下:
1. :将问题分解为规模更小的子问题。
2. :将这些规模更小的子问题逐个击破。
3. :将已解决的子问题合并,最终得出“母”问题的解

例:Fibonacci(上交大复试)

题目描述

斐波那契数列{0,1,1,2,3,5,8,13,21,34,55...}由递归定义: F0=0 F1=1 Fn=Fn-1+Fn-2,n>=2 编写一个程序来计算斐波那契数列。

输入描述:每个情况都包含一个数字 n,您应该计算 Fn.(0<=n<=30) 。

输出描述:对于每种情况,在单独的行上打印一个数字 Fn,这意味着第 n 个斐波那契数列.

输入:1

输出: 1
代码表示
#include <bits/stdc++.h>
using namespace std;
int feibo(int n){
	if(n==0){
		return 0;
	}else if(n==1){
		return 1;
	}else{
		return feibo(n-1)+feibo(n-2);
	}
}
int main() {
    int n;
    while (scanf("%d",&n)!=EOF){
    	printf("%d",feibo(n));
	}
    return 0;
}

例:二叉树(北大上机)

题目描述:
如下所示,由正整数 1,2,3, …组成了一棵特殊二叉树。我们已知这棵二叉树的最后一个结点是 n 。 现在的问题是,结点 m 所在的子树中一共包括多少个结点。比如, n = 12 m = 3 ,那么上图中的结点 13, 14, 15 及后面的结点都是不存在的,结点 m 所在子树中包括的结点有 3, 6, 7, 12 ,因此结点 m 所在的子树中共有 4 个结点。
输入: 输入数据有多行,每行给出一组测试数据,包括两个整数 m n 1 <=   m <= n <=   1000000000 )。
输出: 对于每组测试数据,输出一行,该行包含一个整数,给出结点 m 所在子树中包括的结点的数目。
样例输入:
3 12
样例输出:
4
代码表示:
#include <bits/stdc++.h>
using namespace std;
int tree(int m,int n){
	if(m>n){
		return 0;//边界情况 
	}else{
		return 1+tree(2*m,n)+tree(2*m+1,n);
	}
}
int main() {
    int m,n;
    while (scanf("%d%d",&m,&n)!=EOF){
    	if(m==0){
    		break;
		}
    	printf("%d",tree(m,n));
	}
    return 0;
}


[蓝桥杯 2015 省 B] 移动距离

题目描述

X 星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3,⋯ 。当排满一行时,从下一行相邻的楼往反方向排号。

比如:当小区排号宽度为 6 时,开始情形如下:

1  2  3  4  5  6
12 11 10 9  8  7
13 14 15 .....

我们的问题是:已知了两个楼号 m 和 n,需要求出它们之间的最短移动距离。(不能斜线方向移动)

输入格式

输入为 3 个整数w,m,n,空格分开,都在 1到 10000 范围内。w 为排号宽度,m,n 为待计算的楼号。

输出格式

要求输出一个整数,表示 m 与 n 两楼间最短移动距离

代码表示
#include <bits/stdc++.h>
using namespace std;
int w,m,n,kx,ky,x=0,y=1;//m坐标x,y;n坐标kx,ky 
int main()
{
    scanf("%d%d%d",&w,&m,&n);
    if(n>m) swap(n,m);
    for(register int i=1;i<=m;i++)//枚举从1到m所有数的坐标
    {
    	if(y%2==1)//正方向
    	{
    		x++;
    		if(x>w) x=w,y++;
		}
		else    //反方向
		{
			x--;
			if(x<1) x=1,y++;
		}
		if(i==n) kx=x,ky=y;    //记录n的坐标
	}
	printf("%d",abs(kx-x)+abs(ky-y));
    return 0;
}
心得体会:

这个代码很巧妙,实际上所列出的数实际是什么根本就不重要,重要的是这个点所在坐标位置数的大小。以此来求解两坐标的距离。abs(kx - x)用于计算目标位置和当前位置在水平方向上的距离差的绝对值。


[蓝桥杯 2017 省 B] 日期问题

题目描述

小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入格式

一个日期,格式是 AA/BB/CC。(0≤A,B,C≤9)

输出格式

输出若干个不相同的日期,每个日期一行,格式是 yyyy-MM-dd。多个日期按从早到晚排列。

#include <bits/stdc++.h>
using namespace std;

char a[20];//存储输入的日期 
int M[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int main()
{
	int l,i,j,k,x,y,z;
	scanf("%s",a);
	l=strlen(a);
	//解析日期中的年份,日期,月份为整数 
	x=(a[0]-48)*10+a[1]-48;
	y=(a[3]-48)*10+a[4]-48; 
	z=(a[6]-48)*10+a[7]-48;
	for(i=1960;i<=2059;i++)
	{
		if(i%400==0||(i%4==0&&i%100!=0))	//判断闰年
			M[2]=29;//将二月的天数设为29 
		for(j=1;j<=12;j++)//遍历每个月 
		{
			for(k=1;k<=M[j];k++)//遍历每个月的每一天 
//这个i%100也就是遍历到某个四位数的年份取其后两位 
				if((x==i%100&&y==j&&z==k)||(z==i%100&&x==j&&y==k)||(z==i%100&&y==j&&x==k))
				{
					cout<<i<<"-";
					if(j<10)
						cout<<0;
					cout<<j<<"-";
					if(k<10)
						cout<<0;
					cout<<k<<endl;
				}	
		}
		M[2]=28;//别忘了 
	}
}
心得体会:

1、在ASCII编码中,数字字符'0'的ASCII码是48,而其后的字符依次递增。因此,通过将字符'a[0]'减去48,可以得到对应的数字值。在这段代码中,a[0]是输入日期字符串的第一个字符,例如'0'、'1'、'2'等。由于这些字符是ASCII码表中的字符表示形式,而我们需要得到的是其对应的数字值,所以需要将字符'0'的ASCII码值48减去。然后,将结果乘以10,以便处理两位数的年份。接下来,从字符'a[1]'中减去48,再将结果与之前的乘积相加,从而得到两位数的年份值。

2、这道题开始处解析日期的时候就很灵活,后续采用暴力循环,接着写if语句来取不同日期的值。

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

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

相关文章

一个命令查看自己的WIFI密码

一个命令查看自己的WIFI密码 忘记wifi密码怎么办&#xff1f;一个命令查看自己的wifi密码。 一、打开命令行 使用快捷键“WinR”&#xff0c;打开运行窗口&#xff0c;输入“cmd”后回车即可。 二、输入命令network shell命令 输入命令network shell&#xff0c;简称netsh&…

Android 面试题及答案整理,最新面试题

Android中Intent的作用及分类 Intent在Android中用作组件之间传递信息&#xff0c;它可以用于启动活动(activity)、服务(service)和发送广播(broadcast)。Intent主要分为显式Intent和隐式Intent两大类。 1、显式Intent&#xff1a; 直接指定了要启动的组件名称&#xff08;比如…

【网络】详解HTTPS及探究加密过程

目录 一、什么是HTTPS1、加密解密是什么2、为什么要加密3、常见的加密方式1、对称加密2、非对称加密 二、探究HTTPS如何实现加密1、方案一----只使用对称加密2、方案二----只使用非对称加密3、方案三----双方都使用非对称加密4、方案四----非对称加密 对称加密5、中间人攻击6、…

企业微信 API 接口调用教程:深入解析企业微信 API 的用法

本文通过 access_token 凭证的方式来讲解怎么调用 企业微信 API&#xff0c;并一步步介绍如何获取企业微信 API 的 corpsecret、corpid、access_token 凭证以及怎么向企业微信的应用发送消息。 企业微信 API 在线地址为&#xff1a;qiyeweixin.apifox.cn/ &#xff0c;这个在线…

STL:List从0到1

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

IO流(5)——转换流

不同编码读取出现乱码的问题 解决方法 字符输入转换流&#xff08;InputStreamReader&#xff09;

pytorch 入门基础知识(Pytorch 01)

一 深度学习基础相关 深度学习三个主要的方向&#xff1a;计算机视觉&#xff0c;自然语言&#xff0c;语音识别。 机器学习核心组件&#xff1a;1 数据集(data)&#xff0c;2 前向传播的model(net)&#xff0c;3 目标函数(loss)&#xff0c; 4 调整模型参数和优化函数的算法…

【Linux-网络编程】

Linux-网络编程 ■ 网络结构■ C/S结构■ B/S结构 ■ 网络模型■ OSI七层模型■ TCP/IP四层模型 ■ TCP■ TCP通信流程■ TCP三次握手■ TCP四次挥手 ■ 套接字&#xff1a;socket 主机IP 主机上的进程&#xff08;端口号&#xff09;■ TCP传输文件 ■ 网络结构 ■ C/S结构…

Java学习记录(二十二)反射,动态代理

反射获取class对象的三种方式 1、Class.forName(全类名) 2、类名.class 3、对象.getClass() 实现代码如下&#xff1a; package com.itazhang.Demo1;public class MyReflectDemo1 {public static void main(String[] args) throws ClassNotFoundException {//第一种获取cl…

Nacos源码流程图

1.Nacos1.x版本服务注册与发现源码 流程图地址&#xff1a;https://www.processon.com/view/link/634695eb260d7157a7bc6adb 2.Nacos2.x版本服务注册与发现源码 流程图地址&#xff1a;https://www.processon.com/view/link/634695fb260d7157a7bc6ae0 3.Nacos2.x版本GRPC…

【Linux进程信号】信号的发送与保存

【Linux进程信号】信号的发送与保存 目录 【Linux进程信号】信号的发送与保存阻塞信号1. 信号其他相关常见概念2. 在内核中的表示3. sigset_t4. 信号集操作函数sigprocmasksigpendingsignal测试这几个系统调用接口 进程地址空间第三讲捕捉信号1. 内核如何实现信号的捕捉2. siga…

Jenkins 面试题及答案整理,最新面试题

Jenkins中如何实现持续集成与持续部署&#xff1f; Jenkins通过自动化构建、测试和部署应用程序来实现持续集成与持续部署&#xff08;CI/CD&#xff09;。这个过程包括以下步骤&#xff1a; 1、源代码管理&#xff1a; Jenkins支持与多种版本控制系统集成&#xff0c;如Git、…

Java项目:55 springboot基于SpringBoot的在线视频教育平台的设计与实现015

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 在线视频教育平台分为管理员和用户、教师三个角色的权限模块。 管理员所能使用的功能主要有&#xff1a;首页、个人中心、用户管理、教师管理、课程信…

绝赞春招拯救计划 -- 操作系统,组成原理,计网

进程和线程 进程 一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间&#xff0c;一个进程可以有多个线程 线程 进程中的一个执行任务&#xff08;控制单元&#xff09;&#xff0c;负责当前进程中程序的执行。一个进程至少有一个线程&#xff0c;一个进程可以…

关于Apache

文章目录 一、httpd 安装组成1、常见http 服务器程序2、apache 介绍和特点2.1 关于apache2.1.1 apache 功能2.1.2 apache特性 2.2 MPM multi-processing module 工作模式2.2.1 prefork2.2.2 worker2.2.3 event 3、Httpd 安装和相关文件3.1 包安装httpd并启动httpd服务3.1.1 版本…

配置vscode环境极简版(C/C++)(图文)

前言 众所周知&#xff0c;vscode是一个代码编辑器&#xff0c;不能直接编译运行我们敲的代码&#xff0c;必须提前配置好环境&#xff0c;而这也是劝退一众小白的一大重要因素&#xff0c;下面我想以一种提纲挈领的方式带大家走一遍从配置环境到运行实操代码的全过程。 安装…

用户故事到需求实例化

用户故事 用户故事是敏捷开发方法中的核心概念之一&#xff0c;它提供了一种简洁的方式来描述软件功能需求&#xff0c;同时强调这些功能为用户或业务带来的价值。用户故事通常是由用户、产品经理或业务分析师编写的简短描述&#xff0c;用于与开发团队沟通需求&#xff0c;并…

面向对象(下)

目录 01、static1.1、static的使用1.2、static应用举例1.3、单例(Singleton)设计模式 02、main方法的语法03、类的成员之四&#xff1a;代码块04、关键字&#xff1a;final05、抽象类与抽象方法5.1、多态的应用&#xff1a;模板方法设计模式(TemplateMethod) 06、接口(interfac…

flink1.18.0 自定义函数 接收row类型的参数

比如sql中某字段类型 array<row<f1 string,f2 string,f3 string,f4 bigint>> 现在需要编写 tableFunction 需要接受的参数如上 解决方案 用户定义函数|阿帕奇弗林克 --- User-defined Functions | Apache Flink

C语言数据结构(7)——树、二叉树前言

欢迎来到博主的专栏——C语言数据结构 博主ID&#xff1a;代码小豪 文章目录 树二叉树特殊二叉树满二叉树完全二叉树 完全二叉树的存储结构 树 树是一个非线性的数据结构&#xff0c;由N个结点构成的集合。 树的各个结点由一个根结点联系起来&#xff0c;这个根节点没有前驱…