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层 则是一个答案 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.mfbz.cn/a/385558.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【易学】周易入门 ③ ( 玄学五术 - 山医命相卜 | 天命无常 唯有德者居之 | 预测学模型 | 五行学说 | 五行相生 | 五行相克 )

文章目录 一、玄学五术 - 山医命相卜二、天命无常 唯有德者居之三、预测学模型四、五行学说1、五行相生2、五行相克 一、玄学五术 - 山医命相卜 玄学五术 : 山 : 修行 " 肉体 " 和 " 精神 " , 以寻求 身心超脱 ; 肉体修行 - 拳法 : 太极拳 , 五禽戏 , 易筋…

那些 C语言指针 你不知道的小秘密 (完结篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

BUUCTF LKWA

1.访问页面。 2.选择 Variables variable 关卡 3.获得flag http://357dab81-78b8-4d74-976a-4a69dd894542.node5.buuoj.cn:81/variables/variable.php?funcpassthru&inputcat%2Fflagflag{0020ced6-8166-4fa5-87a7-7d93ee687c3e}

键盘重映射禁用 CtrlAltDel 键的利弊

目录 前言 一、Scancode Map 的规范 二、禁用 CtrlAltDel 的方法及其缺陷 三、编程实现和测试 3.1 C 实现的简易修改工具 3.2 C# 实现的窗口工具 四、总结 本文属于原创文章&#xff0c;转载请注明出处&#xff1a; https://blog.csdn.net/qq_59075481/article/details…

PySQLRecon:一款功能强大的MSSQL安全测试工具

关于PySQLRecon PySQLRecon是一款功能强大的MSSQL安全测试工具&#xff0c;该工具基于SQLRecon实现其功能&#xff0c;可以帮助广大红队研究人员针对MSSQL执行攻击性安全测试。 环境配置 由于该工具基于Python 3开发&#xff0c;因此我们首先需要在本地设备上安装并配置好Pyt…

鸿蒙小案例-你画我猜

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

小技巧 | 如何将win11回退至win10

当你不小心点错将电脑的win10系统更新成win11系统了&#xff08;但没有完全更新&#xff09;&#xff0c;你会怎么做呢&#xff1f; 1.在“开始”菜单界面点击“设置”选项 2.点击“更新和安全”选项 3.在“更新历史记录”中点击“恢复选项” 4.点击“返回”选项 会弹出以下界面…

three.js 细一万倍教程 从入门到精通(二)

目录 三、全面认识three.js物体 3.1、掌握几何体顶点_UV_法向属性 3.2、BufferGeometry设置顶点创建矩形 3.3、生成酷炫三角形科技物体 四、详解材质与纹理 4.1、初识材质与纹理 4.2、详解纹理偏移_旋转_重复 偏移 旋转 重复 4.3、设置纹理显示算法与mipmap mapFil…

【动态规划】:泰波那契模型_解码方法

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本专栏是关于各种算法的解析&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构专栏&…

【网工】华为设备命令学习(综合实验一)

实验要求和实验成果如图所示。 LSW2不需要其他配置&#xff0c;其下就一台设备&#xff0c;不需要区分。 LSW3配置如下&#xff1a; <Huawei>sy Enter system view, return user view with CtrlZ. [Huawei]un in en //关闭系统提示信息 Info: Information …

LeetCode、72. 编辑距离【中等,二维DP】

文章目录 前言LeetCode、72. 编辑距离【中等&#xff0c;二维DP】题目链接与分类二维DP 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容…

VTK Python PyQt 监听键盘 控制 Actor 移动 变色

KeyPressInteractorStyle 在vtk 中有时我们需要监听 键盘或鼠标做一些事&#xff1b; 1. 创建 Actor&#xff1b; Sphere vtk.vtkSphereSource() Sphere.SetRadius(10)mapper vtk.vtkPolyDataMapper() mapper.SetInputConnection(Sphere.GetOutputPort()) actor vtk.vtkAc…

Vue核心基础6:Vue内置指令、自定义指令、生命周期

1 Vue中的内置指令 <script>const vm new Vue({el: #root,data: {n: 1,m: 100,name: Vue,str: <h3>你好</h3>}})</script> 1.1 v-text <div v-text"name"></div>1.2 v-html <div v-html"str"></div> …

Spring Boot 笔记 012 创建接口_添加文章分类

1.1.1 实体类添加校验 package com.geji.pojo;import jakarta.validation.constraints.NotEmpty; import lombok.Data;import java.time.LocalDateTime;Data public class Category {private Integer id;//主键IDNotEmptyprivate String categoryName;//分类名称NotEmptypriva…

中小学信息学奥赛CSP-J认证 CCF非专业级别软件能力认证-入门组初赛模拟题第一套(完善程序题)

CCF认证CSP-J入门组模拟测试题第一套 三、完善程序题 第一题 九宫格 请完善下面的程序,将1~9个数字分别填人3x3的九宫格中,第一行的三个数字组成一个三位数。要使第二行的三位数是第一行的2倍,第三行的三位数是第一行的3倍且每个格子里的数字都不能重复,现在要求输出所有的填…

python输出字符 2022年12月青少年电子学会等级考试 中小学生python编程等级考试二级真题答案解析

目录 python输出字符 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python输出字符 2022年12月 python编程等级考试级编程题 一、题目要求 …

《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)

文章目录 2.1 Flexbox&#xff1a;灵活的布局解决方案2.1.1 基础知识2.1.2 重点案例&#xff1a;创建一个响应式导航菜单2.1.3 拓展案例 1&#xff1a;卡片布局2.1.4 拓展案例 2&#xff1a;中心对齐的登录表单 2.2 Grid 布局&#xff1a;网格系统的魔力2.2.1 基础知识2.2.2 重…

渗透测试练习题解析 3(CTF web)

1、[网鼎杯 2020 朱雀组]phpweb 1 考点&#xff1a;反序列化漏洞利用 进入靶场&#xff0c;查看检查信息&#xff0c;发现存在两个参数 func 和 p 查看页面源代码 payload&#xff1a;funcfile_get_contents&pphp://filter/resourceindex.php 整理后&#xff0c;就是 PHP 代…

数据结构与算法:单链表

朋友们大家好&#xff0c;本节来到数据结构与算法的新内容&#xff1a;单链表 在上篇文章中&#xff0c;我们知道顺序表通常需要预分配一个固定大小的内存空间&#xff0c; 通常以二倍的大小进行增容&#xff0c;可能会造成空间的浪费&#xff0c;本篇文章我们介绍的链表可以解…

去除vue自带的边距

使用vue时发现总有去不掉的外边距&#xff0c;在index.vue里面怎样设置样式都不管用 查阅资料后发现要在vue项目自带的index.html文件内添加下面的样式代码才行 <style>*{margin: 0;padding: 0;}body,html{margin: 0;padding: 0;} </style>
最新文章