算法基础--递归

news2024/11/27 18:52:08

img

😀前言
递归是一种重要的算法思想,常用于解决问题的分解与求解。在计算机科学中,递归是指一个函数在其定义中调用自身的情况。

🏠个人主页:尘觉主页

文章目录

  • 算法基础--递归
    • 递归
      • 入门例题
        • 递归实现指数型枚举
        • 递归实现排列型枚举
        • 递归实现组合型枚举
      • 迷宫问题
        • 迷宫问题一
        • 迷宫问题二
        • 迷宫问题三

算法基础–递归

递归

递归算法在计算机系统中用栈帮助实现,一般常见的算法有深度优先遍历(DFS),可以解决的问题有迷宫问题是否连通的问题,递推会对应一个递归搜索树,递归搜索树可以帮助我们更好的理解递归的流程,递归要注意的有是否可以进行剪枝,在迷宫问题中,也要考虑是否要保存原有的迷宫。

入门例题

递归实现指数型枚举

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

输入格式
输入一个整数 n。

输出格式
每行输出一种方案。

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

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

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

数据范围
1≤n≤15
输入样例:
3
输出样例:

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

题解:

对于指数型枚举一个数只有选与不选的区分,所以我们从第一个位置,枚举到第n个位置,在第i个位置上,i这个数只有选与不选的区别,选的话我们将st[i]记录为i;不选记录为-1;一直到u>n时枚举了所有的位置,此时输出即可,要注意的是在输出完后要记得return掉

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

using namespace std;

const int N=20;
int n;
int st[N];
void dfs(int u){
    if(u>n){
        for(int i=1;i<=n;i++){
            if(st[i]==1) cout<<i<<" ";
        }
        cout<<endl;
        return ;
    }
    
    st[u]=1;
    dfs(u+1);
    
    st[u]=-1;
    dfs(u+1);
}
int main(){
    cin>>n;
    dfs(1);
    return 0;
}
递归实现排列型枚举

把 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

题解

在排列型枚举中,我们有n个位置,在每个位置上分别枚举这个位置可以放那个数,所以我们有一个path数组来记录排列的方案,使用st的bool数组来判断这个数是否选过。

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

using namespace std;

const int N=15;
int n;
bool st[N];
int path[N];
void dfs(int u){
    if(u>n){//所有位置枚举完成
        for(int i=1;i<=n;i++){
            cout<<path[i]<<" ";
        }
        cout<<endl;
        return ;
    }
    
    for(int i=1;i<=n;i++){//在第u个位置上枚举所有方案,这个位置上可以放置所有没有被用过的数字。
        if(!st[i]){
            path[u]=i;
            st[i]=true;//表示这个数被用过了
            dfs(u+1);
            st[i]=false;//还原状态,保证回溯时下一层递归一致。
        }
    }
}
int main(){
    cin>>n;
    dfs(1);
    
    return 0;
}
递归实现组合型枚举

从 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

题解

在组合数枚举中,我们可以通过认为确定枚举的顺序来通过类似排列数的方法来实现,不同的一点时在排列数枚举时,我们要在传一个参数num表示前一位枚举到那个数字,首先写一个朴素方法,该方法的时间是1601ms

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

using namespace std;

const int N=25;
int n,m;
int path[N];
bool st[N];
void dfs(int u,int num){
    if(u>m){
        for(int i=1;i<=m;i++){
            cout<<path[i]<<" ";
        }
        cout<<endl;
        return;
    }
    
    
    for(int i=1;i<=n;i++){
        if(!st[i]&&i>num){
            st[i]=true;
            path[u]=i;
            dfs(u+1,i);
            st[i]=false;
        }
    }
}
int main(){
    cin>>n>>m;
    dfs(1,0);
    
    return 0;
}

下面做一个优化

我们在递归前提前判断一个,上一个位置的数是否合理,如果后面剩的数字不能满足m个位置和递增的条件就直接return掉,进行剪枝,优化时间复杂度。该方法的时间是103ms

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

using namespace std;

const int N=25;
int n,m;
int path[N];
bool st[N];
void dfs(int u,int num){
    if(num>n-m+u-1)return;
    if(u>m){
        for(int i=1;i<=m;i++){
            cout<<path[i]<<" ";
        }
        cout<<endl;
        return;
    }
    
    
    for(int i=1;i<=n;i++){
        if(!st[i]&&i>num){
            st[i]=true;
            path[u]=i;
            dfs(u+1,i);
            st[i]=false;
        }
    }
}
int main(){
    cin>>n>>m;
    dfs(1,0);
    
    return 0;
}

迷宫问题

通过深度优先搜索(DFS)方法实现。

迷宫问题一

一天蒜头君掉进了一个迷宫里面,蒜头君想逃出去,可怜的蒜头君连迷宫是否有能逃出去的路都不知道。

看在蒜头君这么可怜的份上,就请聪明的你告诉蒜头君是否有可以逃出去的路。

输入格式
第一行输入两个整数 nn 和 mm,表示这是一个 n \times mn×m 的迷宫。

接下来的输入一个 nn 行 mm 列的迷宫。其中 ‘S’ 表示蒜头君的位置,'*‘表示墙,蒜头君无法通过,’.‘表示路,蒜头君可以通过’.'移动,'T’表示迷宫的出口(蒜头君每次只能移动到四个与他相邻的位置——上,下,左,右)。

输出格式
输出一个字符串,如果蒜头君可以逃出迷宫输出"yes",否则输出"no"。

数据范围
1 \le n, m \le 101≤n,m≤10。

输出时每行末尾的多余空格,不影响答案正确性

样例输入1复制
3 4
S**.
…*.
*T
样例输出1复制
no
样例输入2复制
3 4
S
.

***T
样例输出2复制
yes

题解

我们读入所有数据,然后获得起点S的坐标。然后深度优先遍历,在迷宫问题中进入DFS后,要先判断是否到中点,在判断是否是障碍物,然后标记该点访问过了。

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

using namespace std;
const int N=15;
int n,m;
char g[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool st[N][N];
bool dfs(int x,int y){
    if(g[x][y]=='T'){
        return true;
    }
    if(g[x][y]=='*') return false;
    st[x][y]=true;
    for(int i=0;i<4;i++){
        int a=x+dx[i],b=y+dy[i];
        if(a>n||a<=0||b<=0||b>m)continue;
        if(st[a][b])continue;
        if(dfs(a,b)){
            return true;
        }
    }
    return false;
}
int main(){
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            if(g[i][j]=='S'){
                x=i;
                y=j;
            }
        }
    }
    if(dfs(x,y)){
        cout<<"yes"<<endl;
    }else{
        cout<<"no"<<endl;
    }
    
    return 0;
}
迷宫问题二

蒜头君在你的帮助下终于逃出了迷宫,但是蒜头君并没有沉浸于喜悦之中,而是很快的又陷入了思考,从这个迷宫逃出的最少步数是多少呢?

输入格式
第一行输入两个整数 nn 和 mm,表示这是一个 n \times mn×m 的迷宫。

接下来的输入一个 nn 行 mm 列的迷宫。其中 ‘S’ 表示蒜头君的位置,'*‘表示墙,蒜头君无法通过,’.‘表示路,蒜头君可以通过’.'移动,'T’表示迷宫的出口(蒜头君每次只能移动到四个与他相邻的位置——上,下,左,右)。

输出格式
输出整数,表示蒜头君逃出迷宫的最少步数,如果蒜头君无法逃出迷宫输出 -1−1。

数据范围
1 \le n, m \le 101≤n,m≤10。

输出时每行末尾的多余空格,不影响答案正确性

样例输入1复制
3 4
S**.
…*.
*T
样例输出1复制
-1
样例输入2复制
3 4
S
.

***T
样例输出2复制
5

题解

本题要求判断是否可以到达并且要计算出最短路径,其实用宽度优先搜索更为合适,因为宽度优先搜索第一次到达目的地就是最短路径,但是我们使用深度优先也可以实现,我们定义一个最短量来储存最短的路径,当每一次到达目的点就比较一下与最短路的大小,交换最短路径长度,因此我们要遍历所有的可行路径,所以就要回溯访问状态,所以在一个遍历后就要复原,将一个点置为未访问,额额额,在 这道题中,我开始忘了读入n和m所以出现了segment段错误,还检查了好久没查到。

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

using namespace std;
const int N=15;
char g[N][N];
bool st[N][N];
int Min=99999;
int m,n;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void dfs(int x,int y,int stmp){
    if(stmp>Min) return ;
    if(g[x][y]=='T'){
        Min=min(Min,stmp);
        return;
    }  
    st[x][y]=true;
    if(g[x][y]=='*') return ;
    for(int i=0;i<4;i++){
        int a=x+dx[i],b=y+dy[i];
        if(a>n||a<=0||b>m||b<=0) continue;
        if(st[a][b]) continue;
        if(g[a][b]=='*') continue;
        dfs(a,b,stmp+1);
        st[a][b]=false;
        
    }
}
int main(){
    cin>>n>>m;
    int a,b;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            if(g[i][j]=='S'){
                a=i,b=j;
            }
        }
    }
    dfs(a,b,0);
    if(Min==99999){
        cout<<-1<<endl;
    }else{
        cout<<Min<<endl;
    }
    return 0;
}
迷宫问题三

经过思考蒜头君终于解决了怎么计算一个迷宫的最短路问题,于是蒜头君找到一个新的迷宫图,来验证自己是否真的会计算一个迷宫的最短路。

为了检验自己计算的是否正确,蒜头君特邀你一起来计算。

输入格式
第一行输入两个整数 nn 和 mm,表示这是一个 n \times mn×m 的迷宫。

接下来的输入一个 nn 行 mm 列的迷宫。其中’@‘表示蒜头君的位置,’#‘表示墙,蒜头君无法通过,’.‘表示路,蒜头君可以通过’.‘移动,所有在迷宫最外围的’.'都表示迷宫的出口(蒜头君每次只能移动到四个与他相邻的位置——上,下,左,右)。

输出格式
输出整数,表示蒜头君逃出迷宫的最少步数,如果蒜头君无法逃出迷宫输出 -1−1。

数据范围
1 \le n,m \le 151≤n,m≤15。

输出时每行末尾的多余空格,不影响答案正确性

样例输入1复制
9 13
#############
#@…#
#####.#.#.#.#
#…#
#.#.#.#.#.#.#
#.#…#.#
#.#.#.#.#.#.#
#…#
#####.#######
样例输出1复制
11
样例输入2复制
4 6
#.####
#.#.##
#…@#

样例输出2复制
5

题解

该迷宫问题与第二个迷宫问题类似,我们也要求出最短路径,所以一样要使用minn记录短的路径。

但是这个题要注意到达的条件,和第二个迷宫终点判断不一样,这个题要观察迷宫的构造,判断终止条件。所以这道题尽量从1开始存储迷宫图。

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

using namespace std;
const int N=20;
int n,m;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
char g[N][N];
bool st[N][N];
int minn=99999;
void dfs(int x,int y,int stmp){
    if(stmp>minn)return ;
    if(x==0||y==0||x==n+1||y==m+1){
        minn=min(minn,stmp);
        return ;
    }
    st[x][y]=true;
    for(int i=0;i<4;i++){
        int a=x+dx[i],b=y+dy[i];
        if(g[a][b]=='#')continue;
        if(st[a][b])continue;
        dfs(a,b,stmp+1);
        st[a][b]=false;
    }

}
int main(){
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            if(g[i][j]=='@'){
                x=i;y=j;
            }
        }
    }
    dfs(x,y,0);
    if(minn==99999){
        cout<<-1<<endl;
    }else{
        cout<<minn-1<<endl;
    }
    return 0;
}

好了,dfs递归就先写到这里

😁热门专栏推荐
想学习vue的可以看看这个

java基础合集

数据库合集

redis合集

nginx合集

linux合集

手写机制

微服务组件

spring_尘觉

springMVC

mybits

等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持

🤔欢迎大家加入我的社区 尘觉社区

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞

img

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

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

相关文章

gulp的基本使用(一)

gulp的基本使用 开始全局安装gulp-cli本地项目初始化gulp插件的安装查看是否安装成功项目根目录创建gulpfile.js文件运行命令测试结果 开始 全局安装gulp-cli 命令 npm install --global gulp-cligulp-cli作用&#xff1a; gulp的命令行工具&#xff0c;它需要全局安装&…

华为交换机维护——管理接口

常见的设备管理方式有SNMP、Web、Telnet以及通过Console口管理等。从技术的角度分析&#xff0c;网络管理可分为带外管理和带内管理。所谓带内管理&#xff0c;是指网络中的管理数据和业务数据在相同的链路中传输。当管理数据的流量较少时&#xff0c;对整个网络的性能影响不明…

前后端开发之——文章分类管理

原文地址&#xff1a;前后端开发之——文章分类管理 - Pleasure的博客 下面是正文内容&#xff1a; 前言 上回书说到 文章管理系统之添加文章分类。就是通过点击“新建文章分类”按钮从而在服务端数据库中增加一个文章分类。 对于文章分类这个对象&#xff0c;增删改查属于配…

Windows提权—数据库提权-mysql提权mssql提权Oracle数据库提权

目录 Windows 提权—数据库提权一、mysql提权1.1 udf提权1.1.2 操作方法一 、MSF自动化--UDF提权--漏洞利用1.1.3 操作方法二、 手工导出sqlmap中的dll1.1.4 操作方法三、 moon.php大马利用 1.2 mof提权1.3 启动项提权1.4 反弹shell 二、MSSQL提权MSSQL提权方法1.使用xp_cmdshe…

项目管理工具的魔力:团队合作的秘诀大揭秘!

我们知道项目的成败往往取决于人。假如一个项目团队组织不善&#xff0c;即使项目经理能力很强也无法力挽狂澜&#xff0c;甚至被团队束缚。创建更好的项目团队可以从多方面下手其中项目管理工具就是重要的一项&#xff0c;如何利用项目管理工具组建更好的项目团队&#xff1f;…

中国主要河流水系数据

在我国&#xff0c;水系等级划分主要依据流域面积、流量和河流长度等因素。根据《中华人民共和国水资源》的相关规定&#xff0c;我国水系等级大致可以分为以下几类&#xff1a; 一级水系&#xff1a;主要是指国内的大型河流&#xff0c;如长江、黄河、珠江等。这些河流的流域…

java入门-分支与循环

分支结构 分支结构是解决程序选取分支走不同的路线&#xff0c;增加了程序开发的灵活性。java的分支主要由if和switch这两种结构实现。 if 语句 if是分支中最常用的语法&#xff0c;它从形式上有三种形态&#xff1a; if 结构 结构 语法 if(表达式){ //代码块 } 程序案例 i…

基于java+SpringBoot+Vue的学生考勤管理系统设计与实现

基于javaSpringBootVue的学生考勤管理系统设计与实现 开发语言: Java 数据库: MySQL技术: SpringBoot MyBatis工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 登录注册&#xff1a;支持学生、教师和管理员登录和注册。 个人中心&#xff1a;用户可以查看和更新个…

C语言-冒泡排序算法

题目描述 设计一个程序&#xff0c;实现冒泡排序算法&#xff0c;并输出{9,8,7,6,5,4,3,2,1,0} 的排序过程。 输出 每个排序过程输出一行&#xff0c;直到排序完成。 样例输出 Expected 9 8 7 6 5 4 3 2 1 0 0 9 8 7 6 5 4 3 2 1 0 1 9 …

C#学习笔记7:C#面向对象编程方法(1)

今日继续我的C#学习笔记 主要用实际代码编程来学习研究C#面向对象的编程方法&#xff1a;直接看代码及注释即可&#xff1a; 目录 1、对类与对象概念的快速认知&#xff1a; 2、类和对象成员访问控制&#xff1a; 3、类的构造函数和析构函数&#xff1a; 4、类的属性&#xff…

GaussDB云数据库极简版安装与使用-新手指南

一、前言 作为一款领先的企业级数据库管理系统&#xff0c;GaussDB 提供了强大的性能、高度可靠性和丰富的功能&#xff0c;是企业构建可靠、高性能的数据库解决方案的理想选择。 本文主要针对高校和个人测试环境&#xff0c;介绍极简版安装和使用过程&#xff0c;更加适合高…

git 修改历史 commit message

目录 1&#xff0c;修改当前的2&#xff0c;修改历史的1&#xff0c;先查看 log2&#xff0c;开始修改 3&#xff0c;其他注意点1&#xff0c;中途不想修改了2&#xff0c;commit ID 会发生变化3&#xff0c;推送远程4&#xff0c;精准定位 1&#xff0c;修改当前的 直接使用下…

Netty核心原理剖析与RPC实践11-15

Netty核心原理剖析与RPC实践11-15 11 另起炉灶&#xff1a;Netty 数据传输载体 ByteBuf 详解 在学习编解码章节的过程中&#xff0c;我们看到 Netty 大量使用了自己实现的 ByteBuf 工具类&#xff0c;ByteBuf 是 Netty 的数据容器&#xff0c;所有网络通信中字节流的传输都是…

哥哥张国荣逝世21年,唐唐继续发文怀念

一代巨星张国荣&#xff08;哥哥&#xff09;在21年前的愚人节&#xff08;2003年4月1日&#xff09;从香港文华东方酒店一跃而下&#xff0c;终年46岁&#xff0c;当年他的离开令很多歌迷影迷都感到悲痛&#xff0c;当中亦包括了他…… 他就是唐鹤德&#xff08;唐唐&#xff…

FPGA高端图像处理开发板-->鲲叔4EV:12G-SDI、4K HDMI2.0、MIPI等接口谁敢与我争锋?

目录 前言鲲叔4EV----高端FPGA图像处理开发板核心板描述底板描述配套例程源码描述配套服务描述开发板测试视频演示开发板获取 前言 在CSDN写博客传播FPGA开发经验已经一年多了&#xff0c;帮助了不少人&#xff0c;也得罪了不少人&#xff0c;有的人用我的代码赢得了某些比赛、…

SpringBoot整合Netty整合WebSocket-带参认证

文章目录 一. VectorNettyApplication启动类配置二.WebSocketServerBoot初始化服务端Netty三. WebsocketServerChannelInitializer初始化服务端Netty读写处理器四.initParamHandler处理器-去参websocket识别五.MessageHandler核心业务处理类-采用工厂策略模式5.1 策略上下文 六…

【C语言】联合和枚举

个人主页点这里~ 联合和枚举 一、联合体1、联合体类型的声明2、联合体成员的特点3、与结构体对比4、计算联合体大小 二、枚举1、枚举的声明2、枚举的优点3、枚举类型的使用 一、联合体 1、联合体类型的声明 联合体的定义与结构体相似&#xff0c;但是联合体往往会节省更多的空…

分布式光伏电力监控系统解决方案

安科瑞薛瑶瑶18701709087 分布式光伏现状 自发自用、余电上网模式 完全自发自用&#xff08;防逆流&#xff09;模式 全额上网模式 0.4kV并网系统 此图为车间新建屋顶分布式光伏发电项目&#xff0c;建设装机容量为1103.46kWp。组件采用单晶硅功率515Wp及550Wp组件&#xff…

文献学习-25-综合学习和适应性教学:用于病理性胶质瘤分级的多模态知识蒸馏

Comprehensive learning and adaptive teaching: Distilling multi-modal knowledge for pathological glioma grading Authors: Xiaohan Xing , Meilu Zhu , Zhen Chen , Yixuan Yuan Source: Medical Image Analysis 91 (2024) 102990 Key words: 知识蒸馏、模态缺失、胶质瘤…

js实现简单的添加移除水印效果

一、实现场景 在做某些内部管理系统时&#xff0c;需求可能要求增加水印&#xff0c;水印内容通常可能是logo或者用户名手机号。实现效果如图&#xff1a; 以下步骤可实现简单添加或者移除水印&#xff0c;并且可以自定义样式、旋转角度等。 二、实现方式 1、先新建一个js…