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

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层 则是一个答案 returnif(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()){//从队列中弹出队头 tauto 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){//变化后坐标距离相当于原坐标距离+1d[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不同时为0while(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.hqwc.cn/news/468637.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[NSSRound#17 Basic]WEB

1.真签到 看robots.txt 密码先base32再base64得到md5加密的密文&#xff0c;在线解得到密码为Nss hint用16进制转字符串&#xff0c;提示新生赛遇到过 是一个敲击码加密 账号是ctfer,登录之后源码提示在F111n4l.php 要求nss参数若比较等于732339662&#xff0c;但是不能是数…

助眠神器小程序源码|白噪音|小睡眠|微信小程序前后端开源

安装要求和说明后端程序运行环境&#xff1a;NginxPHP7.4MySQL5.6 PHP程序扩展安装&#xff1a;sg11 网站运行目录设置为&#xff1a;public 伪静态规则选择&#xff1a;thinkphp 数据库修改文件路径&#xff1a;/config/database.php需要配置后端的小程序配置文件&#xff0c;…

Unresolved reference: kotlinx 和 Unresolved reference:xxx

Unresolved reference: kotlinx 这个报错是因为build.gradle中忘记apply plugin了 apply plugin: kotlin-android-extensions如下 同步以后再次编译发现报错 Unresolved reference:xxx 是因为用于使用 Gradle 构建的 Kotlin 版本与 IDE 插件中的版本不一样的原因 解决方法 …

片上网络NoC(6)——路由算法

目录 一、概述 二、路由算法的类型 三、避免死锁 四、实现 4.1 源路由实现 4.2 基于节点查找表的路由实现 4.3 组合电路实现 五、总结 一、概述 路由算法&#xff08;routing algorithm&#xff09;&#xff0c;即决定数据包在网络拓扑中从起点到终点路径的算法。路由算…

【HTML】情人节给npy一颗炫酷的爱心

闲谈 兄弟们&#xff0c;这不情人节快要到了&#xff0c;我该送女朋友什么&#x1f381;呢&#xff1f;哦&#xff0c;对了&#xff0c;差点忘了&#xff0c;我好像没有女朋友。不过这不影响我们要过这个节日&#xff0c;我们可以学习技术。举个简单的&#x1f330;&#xff1…

基于 Python 的大数据的电信反诈骗系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

[Linux开发工具]项目自动化构建工具-make/Makefile

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.背景2.依赖关系和依…

《区块链公链数据分析简易速速上手小册》第3章:区块链数据结构(2024 最新版)

文章目录 3.1 区块和交易的结构3.1.1 基础知识3.1.2 重点案例&#xff1a;构建简单的区块链3.1.3 拓展案例 1&#xff1a;验证交易签名生成密钥对签名交易验证签名完整的交易签名与验证演示 3.1.4 拓展案例 2&#xff1a;监听和解析区块链事件代币合约示例&#xff08;Solidity…

电路设计(18)——9路抢答器的设计与制作

1.设计要求 设计、制作一台9路抢答器&#xff0c;抢答器应符合如下工作过程&#xff1a; 每次抢答前&#xff0c;主持人首先按下复位键&#xff0c;将抢答器上“抢答号”数显复位&#xff0c;显示为“0”。接着&#xff0c;主持人念答题内容&#xff0c;念毕即叫“抢答…

详解Vue文件结构+实现一个简单案例

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

【STL】string的模拟实现

string类的模拟实现 一、接口函数总览二、默认成员函数1、构造函数2、拷贝构造函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&#xff08;2&#xff09;写法二&#xff1a;现代写法 3、赋值运算符重载函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&…

【数据结构】链表OJ面试题5《链表的深度拷贝》(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 后三题在这http://t.csdnimg.cn/gbohQ 给定一个链表&#xff0c;判断链表中是否有环。http://t.csdnimg.cn/Rcdyc 给定一个链表&#xff0c;返回链表开始入环的第一个结点。 如果链表无环&#xff0c;则返回 NULLhttp://t.cs…