[蓝桥杯] 递归与递推习题训练

news2025/2/27 4:56:49

 

文章目录

一、递归实现指数型枚举

1、1 题目描述

1、2 题解关键思路与解答

二、递归实现排列型枚举 

2、1 题目描述

2、2 题解关键思路与解答

三、递归实现组合型枚举

3、1 题目描述

3、2 题解关键思路与解答

四、带分数

4、1 题目描述

4、2 题解关键思路与解答

五、费解的开关

5、1 题目描述

5、2 题解关键思路与解答

 六、总结


标题:蓝桥杯——递归与递推习题训练

作者:@Ggggggtm

寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景

  蓝桥杯比赛只有四十天左右啦,最近会按照模块更新一些有关蓝桥杯算法题。学习算法不仅仅是为了参见比赛,更是以后找工作的一个敲门砖。废话不多说,我们直接看题。

一、递归实现指数型枚举

1、1 题目描述

题目来源:《算法竞赛进阶指南》

题目难度:简单

题目描述:

  从 1∼n这 n个整数中随机选取任意多个,输出所有可能的选择方案。

输入格式:

  输入一个整数 n。

输出格式:

  每行输出一种方案。

  同一行内的数必须升序排列,相邻两个数用恰好 1个空格隔开。

  对于没有选任何数的方案,输出空行。

  本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。

数据范围:

  1≤ n≤ 15

输入样例:

3

输出样例:


3
2
2 3
1
1 3
1 2
1 2 3

1、2 题解关键思路与解答

   由于上述题目是要求递归,我们可以通过开一个数组纪录是否选择该数组(0表示还没对该数字进行操作,1表示选择该数字,2表示不选择该数字)。这样通过递归,我们就可以很好的枚举出每一种情况。我们结合代码一起理解一下。

#include<iostream>
using namespace std;

const int N=16;

int n;
int state[N];
void dfs(int a)
{
    if(a>n)
    {
         for(int i=1;i<=n;i++)
         {
             if(state[i]==1)
                printf("%d ",i);
         }
         puts("");
         return;
    }
    
    state[a]=2;
    dfs(a+1);
    //恢复现场
    state[a]=0;
    
    state[a]=1;
    dfs(a+1);
    //恢复现场
    state[a]=0;
}
int main()
{
    cin>>n;
    
    dfs(1);
    return 0;
}

二、递归实现排列型枚举 

2、1 题目描述

题目来源:《算法竞赛进阶指南》

题目难度:简单

题目描述:

  把 1∼n这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。

输入格式:

  一个整数 n。

输出格式:

  按照从小到大的顺序输出所有方案,每行 1 个。

  首先,同一行相邻两个数用一个空格隔开。

  其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。

数据范围:

1≤n≤9

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

2、2 题解关键思路与解答

  这个题的关键就在于是排列。通过递归枚举的方法实现排列,我们需要开两个数组:一个数组是记录还数字是否被使用过(0是未被使用,1是已经使用),另一个数组记录所排序的数字。题目中还要求了字典序,正常从小到大递归就已经是字典序较小的排在前面。我们直接看代码。

#include<iostream>
using namespace std;

const int N=10;

int n;
int state[N];
int used[N];
void dfs(int a)
{
    if(a>n)
    {
        for(int i=1;i<=n;i++)
            printf("%d ",state[i]);
        puts("");
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(used[i]==0)
        {
            state[a]=i;
            used[i]=1;
            dfs(a+1);
            
            used[i]=0;
        }
    }
}
int main()
{
    cin>>n;
    
    dfs(1);
    return 0;
}

三、递归实现组合型枚举

3、1 题目描述

题目来源:《算法竞赛进阶指南》

题目难度:简单

题目描述:

  从 1∼n 这 n个整数中随机选出 m个,输出所有可能的选择方案。

输入格式:

  两个整数 n,m,在同一行用空格隔开。

输出格式:

  按照从小到大的顺序输出所有方案,每行 1 个。

  首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

  其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

数据范围:

  n>0,
  0≤m≤n,
  n+(n−m)≤25

输入样例:

5 3

输出样例:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5 

3、2 题解关键思路与解答

  组合与排列十分相似,但又有些不同。组合特殊的是 1,2,3 与 2,1,3 与 3,2,1相同的,算是一种组合类型。题目中要求的同一行内的数升序排列。怎么定义升序呢?我们可以人为的选数字为升序。我们可以把整体的升序看成局部的升序,只要是满足后一个数比前一个数大即可。

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

int n,m;

const int N=26;

int way[N];
void def(int a,int start)
{
    if(a-1+n-start+1<m)  //剪枝
        return;
    if(a==m+1)
    {
        for(int i=1;i<=m;i++)
        {
            printf("%d ",way[i]);
        }
        printf("\n");
        return;
    }
    for(int i=start;i<=n;i++)
    {
        way[a]=i;
        def(a+1,i+1);
    }
}
int main()
{
    cin>>n>>m;
    
    def(1,1);
    return 0;
}

四、带分数

4、1 题目描述

题目来源:第四届蓝桥杯省赛C++B/C组

题目难度:中等

题目描述:

  100可以表示为带分数的形式:100=3+69258 / 714

  还可以表示为:100=82+3546 / 197

  注意特征:带分数中,数字 1∼9 分别出现且只出现一次(不包含 0)。

  类似这样的带分数,100 有 11 种表示法。

输入格式:

  一个正整数。

输出格式:

  输出输入数字用数码 1∼9不重复不遗漏地组成带分数表示的全部种数。

数据范围:

 1≤N<106

输入样例1:

100

输出样例1:

11

输入样例2:

105

输出样例2:

6

4、2 题解关键思路与解答

  我们可以把带分数的形式看成一个公式:n = a + b / c 。也就是a、b和c 的数字 中1∼9 分别出现且只出现一次。那我们就可以想枚举a和c的情况,然后通过公式 b = c*n-c*a 计算出b的值。再把b的每一位拿出来看看时候符合题目所要求的情况。我们直接结合代码一起理解一下。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

const int N=12;

int n,ans;
bool st[N],backup[N];

bool check(int a,int c)
{
    long long b=n*(long long)c-a*c;
    
    memcpy(backup,st,sizeof(st));
    while(b)
    {
        int x=b%10;
        b/=10;
        if(!x || backup[x])
            return false;
        backup[x]=true;
    }
    for(int i=1;i<=9;i++)
    {
        if(!backup[i])
            return false;
    }
    return true;
}
void dfs_c(int u,int a,int c)
{
    if(u>9)
        return;
    if(check(a,c))
        ans++;
    for(int i=1;i<=9;i++)
    {
        if(!st[i])
        {
            st[i]=true;
            dfs_c(u+1,a,c*10+i);
            
            st[i]=false;
        }
    }
}
void dfs_a(int u,int a)
{
    if(a>=n)
        return;
    if(a)
        dfs_c(u,a,0);
    for(int i=1;i<=9;i++)
    {
        if(!st[i])
        {
            st[i]=true;
            dfs_a(u+1,a*10+i);
            
            st[i]=false;
        }
    }
}
int main()
{
    cin>>n;
    
    dfs_a(0,0);
    
    cout<<ans<<endl;
    return 0;
}

五、费解的开关

5、1 题目描述

题目来源:《算法竞赛进阶指南》

题目难度:中等

题目描述:

  你玩过“拉灯”游戏吗?

  25 盏灯排成一个 5×5 的方形。

  每一个灯都有一个开关,游戏者可以改变它的状态。

  每一步,游戏者可以改变某一个灯的状态。

  游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。

  我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。

下面这种状态:

10111
01101
10111
10000
11011

在改变了最左上角的灯的状态后将变成:

01111
11101
10111
10000
11011

再改变它正中间的灯后状态将变成:

01111
11001
11001
10100
11011

  给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。

输入格式:

  第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。

  以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。

  每组数据描述了一个游戏的初始状态。

  各组数据间用一个空行分隔。

输出格式:

  一共输出 n 行数据,每行有一个小于等于 66 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。

  对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。

数据范围:

0<n≤500

输入样例:

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

输出样例:

3
2
-1

5、2 题解关键思路与解答

  由于每个灯是数字 1 表示一盏开着的灯,用数字 0 表示关着的灯,我们就一行一行就行看。一行有五个灯,我们把代表灯的状态的数字看作一个数的二进制位。也就是一行有32种情况。整体的思路就是下一行影响上一行,我们需要做的是首先枚举第一行的32种情况,接着调整完前四行,最后看第五行是否为全亮即可。我们直接看代码:

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int N=6;
char g[N][N],backup[N][N];
int dx[5]={-1,0,1,0,0},dy[5]={0,0,0,-1,1};

void turn(int x,int y)
{
    for(int i=0;i<5;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0 || a>4 || b<0 || b>4)
            continue;
        g[a][b]^=1;
    }
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int res=10;
        for(int i=0;i<5;i++)
            cin>>g[i];
        for(int op=0;op<32;op++)
        {
            int step=0;
            memcpy(backup,g,sizeof(g));
            for(int i=0;i<5;i++)
            {
                if(op>>i&1)
                {
                    step++;
                    turn(0,i);
                }
            }
            for(int i=0;i<4;i++)
            {
                for(int j=0;j<5;j++)
                {
                    if(g[i][j]=='0')
                    {
                        step++;
                        turn(i+1,j);
                    }
                }
            }
            
            bool back=false;
            for(int i=0;i<5;i++)
            {
                if(g[4][i]=='0')
                {
                    back=true;
                    break;
                }
            }
            if(!back)
                res=min(res,step);
            memcpy(g,backup,sizeof(g));
        }
        if(res>6)
            res=-1;
        cout<<res<<endl;
    }
    return 0;
}

 六、总结

  通过上面的习题练习,我们发现用递归去枚举也很简单。同时,我们也要掌握上面的递归枚举的思路和方法。在很多情况下,我们可以多开数组来进行记录或者操作,会给我们带来很大的便利。

  递归与递推的练习就到这里,希望以上内容对你有所帮助。

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

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

相关文章

基于STM32设计的倒车雷达系统(超声波模块多方位测距应用)

一、项目背景 汽车高科技产品家族中,专为倒车泊位设置的“倒车雷达”应运而生,倒车雷达的加装可以解决驾驶人员的后顾之忧,大大降低到车事故的发生。汽车倒车雷达全称为“倒车防撞雷达”,也叫“泊车辅助装置”,是汽车泊车安全辅助装置,能以声音或者更为直观的显示来告知…

比特数据结构与算法(第三章_下)队列的概念和实现(力扣:225+232+622)

一、队列&#xff08;Queue&#xff09;队列的概念&#xff1a;① 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。② 入队列&#xff0c;进行插入操作的一端称为 队尾。出队列&#xff0c;进行删除操作的一端称为 队头。③ 队列中的元素…

小公司“混”的3年,我认真做了5件事,真的受益终生

小公司“混”的3年&#xff0c;我认真做了5件事&#xff0c;真的受益终生 目录&#xff1a;导读 功能测试很重要但不值钱 自动化测试在小公司没市场&#xff0c;但是你得会 给自己的一些忠告 第一件事&#xff1a;分清阶段&#xff0c;制定计划 第二件事&#xff1a;梳理…

SQL零基础入门学习(三)

SQL零基础入门学习&#xff08;二&#xff09; SQL WHERE 子句 WHERE 子句用于提取那些满足指定条件的记录。 SQL WHERE 语法 SELECT column1, column2, ... FROM table_name WHERE condition;参数说明&#xff1a; column1, column2, …&#xff1a;要选择的字段名称&…

进程或线程终止是否会释放锁

线程锁的必要性比如一个多线程抢票程序&#xff0c;tickets作为临界资源&#xff0c;所有的线程都要对它进行判断ticket是否大于0&#xff0c;以及ticket–的操作。用ticket–操作举例&#xff0c;虽然他看起来是一行C语言的代码&#xff0c;但是实际上它的底层汇编经历了三个阶…

OSS Compass 开源指南针发布,剑指开源生态健康

估量有尺&#xff0c;开源有道。2 月 21 日&#xff0c;开源指南针 OSS Compass 发布会在北京顺利举行。OSS Compass 的发布&#xff0c;标志着我国首个开源生态健康评估平台正式诞生。发布会上介绍了 OSS Compass 的理论研究及实践成果&#xff0c;公布了 OSS Compass 开源社区…

图解操作系统

硬件结构 CPU是如何执行程序的&#xff1f; 图灵机的工作方式 图灵机的基本思想&#xff1a;用机器来模拟人们用纸笔进行数学运算的过程&#xff0c;还定义了由计算机的那些部分组成&#xff0c;程序又是如何执行的。 图灵机的基本组成如下&#xff1a; 有一条「纸带」&am…

【数据库】redis 配置文件与发布订阅

目录 配置文件 一&#xff0c;Units 二&#xff0c; INCLUDE 三&#xff0c;NETWORK 1&#xff0c; bind 2&#xff0c; tcp-backlog 3&#xff0c;timeout 4&#xff0c; tcp-keepalive 四&#xff0c;GENERAL 1&#xff0c;daemonize 2&#xff0c; pidfile 3&…

ESP32设备驱动-内置霍尔磁力传感器数据读取

内置霍尔磁力传感器数据读取 文章目录 内置霍尔磁力传感器数据读取1、ESP32霍尔磁力传感器介绍2、软件准备3、硬件准备4、读取霍尔磁力传感值5、运行结果ESP32开发板具有内置霍尔效应传感器,可检测周围磁场的变化。本文将介绍如何在Arduino IDE中读取ESP32霍尔效应传感器的数据…

【VUE3.0_CSS功能】

CSS功能组件css作用域深度选择器&#xff08;标签名空格:deep(标签名)&#xff09;插槽选择器&#xff08;:soltted(标签名)&#xff09;全局选择器&#xff08;:global(类名)&#xff09;动态CSS&#xff08;v-bind&#xff09;useCSSModule拓展知识&#xff1a;deep的写法组件…

iPhone更换电池和屏幕后提醒非原厂配件的操作办法

---开局一张图&#xff0c;内容全靠编系列&#xff01; 【图】 自从在iPhone系统iOS13开始支持原厂配件检测后&#xff0c;可以说苹果也动起了维修站商家利益的这块蛋糕。道理自然简单&#xff0c;卷嘛&#xff01;全球汽车行业也不是靠卖新车才赚钱的&#xff0c;各种交通事故…

MATLAB/Simulink 通信原理及仿真学习(二)

文章目录MATLAB/Simulink 通信原理及仿真学习&#xff08;二&#xff09;simulink仿真常用的Simulink库1. 信号源模块库2. 数序运算模块3. 信号输出模块库4.仿真搭建5.搭建自己的库6.S-函数编写MATLAB/Simulink 通信原理及仿真学习&#xff08;二&#xff09; simulink仿真 交…

resp连接redis服务器

修改redis的配置文件使得windows的图形界面客户端可以连接redis服务器 resp安装好以后&#xff0c;可以在linux端打开redis.conf中做以下操作&#xff0c;使得windows的图形界面客户端可以连接redis服务器 方法一&#xff1a; 1&#xff0c;在redis.conf文件中添加bind 在文件…

K8s中gRpc通信负载均衡失效

上篇文章在做 整合K8sSpringCloudK8sSpringBootgRpc 时&#xff0c;发现K8s中使用gRpc通信&#xff0c;负载均衡功能失效查了下gRpc的最佳实践&#xff0c;找到这里Load balancingSome load balancers dont work effectively with gRPC. L4 (transport) load balancers operate…

【JUC2022】第二章 多线程锁

【JUC2022】第二章 多线程锁 文章目录【JUC2022】第二章 多线程锁一、乐观锁与悲观锁1.悲观锁2.乐观锁二、八锁案例1.标准情况&#xff0c;有a、b两个线程&#xff0c;请问先打印邮件还是短信【结果&#xff1a;邮件】2.sendEmail方法中加入暂停3秒钟&#xff0c;请问先打印邮件…

筑基六层 —— 整型提升及实用调式技巧

目录 一.修炼必备 二. 整型提升 三.实用调式技巧 一.修炼必备 1.入门必备&#xff1a;VS2019社区版&#xff0c;下载地址&#xff1a;Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com) 2.趁手武器&#xff1a;印象笔记/有道云笔记 3.修炼秘籍&…

植物大战 仿函数——C++

容器适配器 容器适配器不支持迭代器。栈这个东西&#xff0c;让你随便去遍历&#xff0c;是不好的。他是遵循后进先出的。所以他提供了一个街头top取得栈顶数据。 仿函数 仿函数&#xff08;functor&#xff09;是C中一种重载了函数调用运算符&#xff08;operator()&#x…

HTTP安全与HTTPS协议

目录 Http协议的安全问题 常见的加密方式 防止窃听 单向散列函数 单向散列值的特点 加密与解密 对称加密与非对称加密 对称加密的密钥配送问题 密钥配送问题的解决 非对称加密 前言&#xff1a; 公钥与私钥 非对称加密过程 混合密码系统 前言&#xff1a; 混合…

vue3中使用jszip压缩文件

1、安装依赖 npm install jszip npm install file-saver --save 2、使用 <template><el-card class"mb15"><template #header><span>jszip</span></template><!-- 二维码容器 --><div id"qrCodeBox">&…

手把手教你,解决C盘分区不足,C盘怎么扩大磁盘分区

由于在磁盘分区中&#xff0c;C盘是很重要的一个磁盘&#xff0c;为了保证C盘有足够的磁盘分区。其中扩大C盘分区很常见的操作之一。那么&#xff0c;C盘怎么扩大磁盘分区&#xff1f;在本文中&#xff0c;易我小编将全面地讲解C盘合并分区的方法。 一、为什么C盘怎么扩大磁盘分…