BFS与DFS初级练习(排列数字,n-皇后,走迷宫)

news2025/1/19 11:04:10

BFS与DFS初步了解

DFS(深度优先搜索)和BFS(广度优先搜索)是两种常用的图遍历算法。

DFS是一种递归的搜索算法,它从起始节点开始,沿着路径依次访问与当前节点相邻的未访问节点,直到无法继续访问时回溯到上一个节点,并选择另一个未访问节点进行访问,直到所有节点都被访问完毕或者找到目标节点。DFS的特点是先深度后广度,即优先探索深度方向的节点。

BFS是一种迭代的搜索算法,它从起始节点开始,依次访问与当前节点相邻的未访问节点,并将这些节点按照访问的顺序加入一个队列中,然后再按照队列中节点的顺序依次访问队列中的节点,直到队列为空或者找到目标节点。BFS的特点是先广度后深度,即优先探索广度方向的节点。

这两种算法的实际中运用十分多,在竞赛中很多题也能用搜索解决,所以对DFS,BFS的掌握就十分重要。下面是一些dfs,bfs经典但是难度又不高的例题

BFS

排列数字​​​​​​

给定一个整数 n,将数字 1∼n排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入格式

共一行,包含一个整数 n。

输出格式

按字典序输出所有排列方案,每个方案占一行。

数据范围

1≤n≤7

输入样例:

3

输出样例:

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

DFS关键在于递归结束条件的选择,状态标记,递归后的恢复。

像这道题就可以使用深搜解决

我们可以构造如图的一颗树,每次选择一个数都是往下,如果往下没有路了,则回溯到上一步,经典的DFS操作。

想要实现上图的操作,我们需要一个st数组,用于记录每个点是否被访问过,辅助搜索。

此题中还需要递归后恢复标记,不然回溯之后没有未被访问的点可以使用。

#include<iostream>
using namespace std;
const int N = 10;
int n;
//用于记录路径
int path[N];
//记录某个点是否使用过 用于辅助dfs操作
bool st[N];

void dfs(int u)
{
    //如果到了末尾 第N层 则是一个答案 return
    if(u == n) 
    {
        for(int i = 0;i<n;i++) printf("%d ",path[i]);
        printf("\n");
        return;
    }

    for(int i = 1;i<=n;i++)
    {
        //如果这个点没有被使用过 则可以填入数字
        if(st[i] != true)
        {
            //进入下一层使要修改数据
            path[u] = i;
            st[i] = true;
            dfs(u+1);
            //回溯要及时改回来数据
            st[i] = false;
        }
    }

}

int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

n-皇后问题

n−皇后问题是指将 n 个皇后放在 n×n的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

1_597ec77c49-8-queens.png

现在给定整数 n,请你输出所有的满足条件的棋子摆法。

输入格式

共一行,包含整数 n。

输出格式

每个解决方案占 n行,每行输出一个长度为 n的字符串,用来表示完整的棋盘状态。

其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。

每个方案输出完成后,输出一个空行。

注意:行末不能有多余空格。

输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围

1≤n≤9

输入样例:

4

输出样例:

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

n皇后是非常经典的一道DFS题,学会这道题对DFS的理解会更加透彻。

首先理解什么是n皇后问题,即在一个nxn的棋盘上放置皇后,其中任意两个皇后都不能在同一行,同一列,同一正对角线,同一负对角线上。

棋盘是个矩阵,我们一行一行的继续计算,还是核心思想:递归结束条件的选择,状态标记,递归后的恢复。

状态标记:

因为我们是一行一行进行计算,每行我们只放一个,所以行的状态我们不用进行标记。所以我们需要三个数组进行标记状态:

行,列,对角线我们都从 0 ~n进行编号

col[N]   用于标记某列上是否有皇后 有为1 没有为0

dg[N]    用于标记某正对角线上是否有皇后 有为1 没有为0

udg[N]  用于标记某负对角线上是否有皇后 有为1 没有为0

对列的标记十分简单,但是对角线的标记不是很好理解,下面利用画图辅助理解

我们将棋盘放到坐标系,以正对角线为例,用图中的画法,我们可以发现,每条对角线的编号正好是直线在y轴上的截距,直线方程为: y = -x + b

我们需要的是b,所以 b = y + x   这样我们就得到了正对角线的编号方程,代码中y轴对应行u,x轴对应 y轴 i ,所以正对角线的编号方程为 u+i

同理可以得到副对角线方程 u-i,因为是相减,可能会有负数出现,所以加上偏移量n,防止负数出现

准备工作已经完成,接下来是DFS的思路

递归结束条件的选择:

要求col[N],dg[N],udg[N]三个数组同时为0,即都没有使用过时,放置皇后。  

递归后的恢复:

递归结束后要恢复状态,以便下一次递归

​
#include<iostream>
using namespace std;
const int N = 20;
//dg[N]记录正对角线上元素是否被使用过 udg记录负对角线上元素是否被使用过 col记录列
int dg[N],col[N],udg[N];
//记录操作
char path[N][N];
int n;

void dfs(int u)
{
    //u表示行 到最后一行输出
    if(u == n)
    {
        //输出
        for(int i = 0;i<n;i++)
        {
            for(int j= 0;j<n;j++)
            {
                printf("%c",path[i][j]);
            }
            printf("\n");
        }
        printf("\n");
        return;
    }

    for(int i = 0;i<n;i++)
    {
        //col dg udg数组初始为0即未被使用过 所以只有三个全未被使用过才能记录数字
        if(col[i] == 0 && dg[u+i] == 0 && udg[u-i+n] == 0)
        {
            //往下走要修改状态
            path[u][i] = 'Q';
            col[i] = dg[u+i] = udg[u-i+n] = 1;
            dfs(u+1);
            //回溯要修正状态
            path[u][i] = '.';
            col[i] = dg[u+i] = udg[u-i+n] = 0;
        }
    }
}


int main()
{
    cin>>n;
    //初始化为.
    for(int i = 0;i<n;i++)
        for(int j =0;j<n;j++)
            path[i][j] = '.';

    dfs(0);
    return 0;
}

BFS

 迷宫问题

给定一个 n×m的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,11表示不可通过的墙壁。

最初,有一个人位于左上角 (1,1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。

数据保证 (1,1)处和 (n,m) 处的数字为 0,且一定至少存在一条通路。

输入格式

第一行包含两个整数 n 和 m。

接下来 n 行,每行包含 m个整数(0 或 1),表示完整的二维数组迷宫。

输出格式

输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围

1≤n,m≤100

输入样例:

5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:

8

迷宫问题也是一种最短路问题,解决方法很多,这里我们利用BFS解决。

BFS因为是一层一层搜索,所以到图中权值都为1时,每第一次搜到这个点,一定是最短路径

BFS通常使用队列辅助计算

如图是BFS的思路 也是模板,我们可以将迷宫看成图,从左上角开始移动,可以上下左右移动,所以我们可以将这点的上下左右看成一层,我们一直枚举一层中的所有元素,如果符合条件,就入队,往下一层枚举。 总的来说 BFS难度要比DFS低,也更加容易理解

图中数字表示层数

题解中利用了STL中的queue与pair,如果stl不熟练可以自行上网搜索

代码中注释写的十分详细,所以也不过多赘述。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 110;
int n,m;

//用于存储地图 0可以通过 -1表示路障
int g[N][N];
//用于存储每个点的距离 为-1表示没到过这个点
int d[N][N];
typedef pair<int,int> PII;
queue<PII> q;
//记录下这个点是从哪个点走过来的,保存路径
PII Prev[N][N];

int bfs()
{
    //从左上角0,0开始走
    q.push({0,0}); 
    //刚开始每个点的距离要初始化为-1 因为每个点都没到过
    memset(d,-1,sizeof d);
    //从左上角0开始走
    d[0][0] = 0;
    //用dx dy数组表示在地图中往上下左右走的坐标变化
    int dx[4] = {1,0,-1,0},dy[4] = {0,1,0,-1};
    //队列不为空
    while(!q.empty())
    {
        //从队列中弹出队头 t
        auto t = q.front();
        q.pop();
        //表示往上下左右走四个方向试探
        for(int i = 0;i<4;i++)
        {
            //通过四次循环列出四个方向走的坐标,后面再进行判断 这样可以剩下4个判断
            int x = dx[i]+t.first,y = dy[i]+t.second;
            //x,y坐标要在图内,图上为0才能走(-1表示路障),d[x][y]要为-1(表示未到过这个点)
            if(x >= 0 && x<n && y>=0 && y<m && g[x][y] == 0 && d[x][y] == -1)
            {
                //变化后坐标距离相当于原坐标距离+1
                d[x][y] = d[t.first][t.second]+1;
                //入队变换后坐标 作为新的起点
                q.push({x,y});
                //记录下这个点是从哪个点走过来的,保存路径
                Prev[x][y] = t;
            }
        }
    }
    
    //从后往前倒退路径
    int x = n-1,y = m-1;
    //x与y不同时为0
    while(x||y)
    {
        cout<<x<<" "<<y<<endl;
        x = Prev[x][y].first,y = Prev[x][y].second;
    }
    
    //返回到右下角的距离
    return d[n-1][m-1];
}

int main()
{
    cin>>n>>m;
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<m;j++)
        {
            cin>>g[i][j];
        }
    }
    
    cout<<bfs()<<endl;
    return 0;
}

此篇为新手学习总结用,为了加深记忆,所以有错误可以指出,谢谢大家观看

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

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

相关文章

Pytorch的可视化

1 使用 wandb进行可视化训练过程 本文章将从wandb的安装、wandb的使用、demo的演示进行讲解。 1.1 如何安装wandb&#xff1f; wandb的安装比较简单&#xff0c;在终端中执行如下的命令即可&#xff1a; pip install wandb在安装完成之后&#xff0c;我们需要&#xff0c;去…

【力扣】5.最长回文子串

这道题我主要是通过动态规划来进行解题&#xff0c;看了我好久&#xff08;解析&#xff09;&#xff0c;生疏了呀。 首先就是判断一个字符串是不是回文&#xff0c;我们可以设置两个指针&#xff0c;从前往后进行判断即可&#xff0c;运用暴力解题法&#xff0c;这里运用的动…

【C++】内存详解(堆,栈,静态区)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【FPGA】VHDL:八段码到8421BCD码转换电路

目录 EDA设计基础练习题 &#xff1a; 实验要求如下&#xff1a; 代码 八段码到8421BCD码转换电路 8421BCD码到八段码转换电路 八段码到8421BCD~运行结果展示 8421BCD转八段码~运行结果展示 特别注意 软件&#xff1a;Quartus II 13.0 (64-bit) 语言&#xff1a;VHDL E…

书生谱语-基于 InternLM 和 LangChain 搭建知识库

大语言模型与外挂知识库&#xff08;RAG&#xff09;的优缺点 RAG方案构建与优化 作业 在创建web_demo时&#xff0c;需要根据教程将服务器端口映射到本地端口&#xff0c;另外需要将链接的demo从服务器中复制出来&#xff0c;不要直接从服务器打开demo页面&#xff0c;不然会…

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

目录: OpenID 与 OAuth2 基础知识Blazor wasm Google 登录Blazor wasm Gitee 码云登录Blazor OIDC 单点登录授权实例1-建立和配置IDS身份验证服务Blazor OIDC 单点登录授权实例2-登录信息组件wasmBlazor OIDC 单点登录授权实例3-服务端管理组件Blazor OIDC 单点登录授权实例4 …

低资源学习与知识图谱:构建与应用

目录 前言1 低资源学习方法1.1 数据增强1.2 特征增强1.3 模型增强 2 低资源知识图谱构建与推理2.1 元关系学习2.2 对抗学习2.3 零样本关系抽取2.4 零样本学习与迁移学习2.5 零样本学习与辅助信息 3 基于知识图谱的低资源学习应用3.1 零样本图像分类3.2 知识增强的零样本学习3.3…

鸿蒙小案例-你画我猜

鸿蒙小案例-你画我猜 1.准备组件(组件布局) 2.实现跟随鼠标画笔画出图案功能 3.实现复制上面的画笔的图案功能 4.其他小功能1.组件的准备 画布的组件官方给的API是Canvas&#xff0c;需要传递一个参数CanvasRenderingContext2D 直接搜索API 使用官方案例 private settings: …

【GO语言卵细胞级别教程】05.项目创建和函数讲解

感谢&#xff01;点点赞和评论呀&#xff01;我将继续更新 目录&#xff1a; 感谢&#xff01;点点赞和评论呀&#xff01;我将继续更新0.创建项目1.函数的引入2.注意事项3.详细介绍3.1 形参介绍 4.导入包4.1 基本知识4.2 注意事项 5.init函数6.匿名函数 0.创建项目 创建目录 …

力扣精选算法100道——矩阵区域和 (前缀和专题)

目录 &#x1f388;了解题意 &#x1f388;算法原理 &#x1f388;实现代码 &#x1f388;了解题意 给定一个大小为 m x n 的矩阵 mat 和一个整数 k&#xff0c;你需要计算一个新的矩阵 answer&#xff0c;其中每个 answer[i][j] 表示矩阵 mat 中以坐标 (i, j) 为中心、边…

JavaScript 事件循环:Event Loop

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 事件循环 是 web 开发中的一个核心概念&#xff0c;它是 JavaScript…

【Linux】线程概念和线程控制

线程概念 一、理解线程1. Linux中的线程2. 重新定义线程和进程3. 进程地址空间之页表4. 线程和进程切换5. 线程的优点6. 线程的缺点7. 线程异常8. 线程用途9. 线程和进程 二、线程控制1. pthread 线程库&#xff08;1&#xff09;pthread_create()&#xff08;2&#xff09;pth…

[Doris] Doris的安装和部署 (二)

文章目录 1.安装要求1.1 Linux操作系统要求1.2 软件需求1.3 注意事项1.4 内部端口 2.集群部署2.1 操作系统安装要求2.2 下载安装包2.3 解压2.4 配置FE2.5 配置BE2.6 添加BE2.7 FE 扩容和缩容2.8 Doris 集群群起脚本 3.图形化 1.安装要求 1.1 Linux操作系统要求 1.2 软件需求 1…

Acwing---842.排列数字

排列数字 1.题目2.基本思想3.代码实现 1.题目 给定一个整数 n&#xff0c;将数字 1∼n排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 n。 输出格式 按字典序输出所有排列方案…

mysql Day05

sql性能分析 sql执行频率 show global status like Com_______ 慢查询日志 执行时间超过10秒的sql语句 profile详情 show profiles帮助我们了解时间都耗费到哪里了 #查看每一条sql的耗时情况 show profiles#查看指定query_id的sql语句各个阶段的耗时情况 show profile fo…

【电路笔记】-并联电感

并联电感 文章目录 并联电感1、概述2、并联电感示例13、互耦并联电感器4、并联电感示例25、并联电感示例36、总结当电感器的两个端子分别连接到另一个或多个电感器的每个端子时,电感器被称为并联连接在一起。 1、概述 所有并联电感器上的压降将是相同的。 然后,并联的电感器…

MATLAB 1:基础知识

MATLAB中的数据类型主要包括数值类型、逻辑类型、字符串、函数句柄、结构体和单元数组类型。这六种基本的数据类型都是按照数组形式存储和操作的。 MATLAB中还有两种用于高级交叉编程的数据类型&#xff0c;分别是用户自定义的面向对象的用户类类型和Java类类型。 1.1.1数值类…

java微服务面试篇

目录 目录 SpringCloud Spring Cloud 的5大组件 服务注册 Eureka Nacos Eureka和Nacos的对比 负载均衡 负载均衡流程 Ribbon负载均衡策略 自定义负载均衡策略 熔断、降级 服务雪崩 服务降级 服务熔断 服务监控 为什么需要监控 服务监控的组件 skywalking 业务…

【白话前端】快速区分webGL,webGPU,unity3D和UE4

在3D图形渲染的渲染领域&#xff0c;很多友友们对上述概念傻傻分不清&#xff0c;站在前端开发角度&#xff0c;我用简单语言说下&#xff0c;结论在文章最后。 一、四者都能进行3D图形渲染 它们之间有一些区别&#xff0c;下面我将对它们进行简单的区分&#xff1a; WebGPU&a…

【STM32 CubeMX】HAL库的本质读写寄存器

文章目录 前言一、HAL库的本质1.1 HAL库的本质是操作寄存器1.2 自己实现HAL_GPIO_WritePin寄存器通过寄存器的操作点灯代码概况Port bit set/reset register寄存器 总结 前言 在嵌入式系统开发中&#xff0c;HAL&#xff08;Hardware Abstraction Layer&#xff09;库是一个重…