【算法】DFS与BFS

news2025/1/13 7:26:19

作者:指针不指南吗
专栏:算法篇

🐾题目的模拟很重要!!🐾

文章目录

  • 1.区别
  • 2.DFS
    • 2.1 排列数字
    • 2.2 n-皇后问题
  • 3.BFS
    • 3.1走迷宫

1.区别

搜索类型数据结构空间用途过程
DFSstackO( n )不能用于最短路搜索到最深处,回溯
BFSqueueO( n 2 n^2 n2 )可以用于最短路从起点开始,搜索相邻的;再以相邻的位起点,继续

这里用两个图来形象的模拟过程
深搜——一条路走到黑
在这里插入图片描述
广搜——眼观八方
在这里插入图片描述

2.DFS

  • 每一个DFS都对应一个搜索树;

  • DFS俗称暴搜,其中有顺序的,经常用到DFS;

  • 回溯的时候一定要恢复现场;

  • 剪枝就是判断出来当前的方案不合法,不再继续往下深搜,直接回溯;

只说知识,有点抽象,根据两个题来理解一下。

2.1 排列数字

给定一个整数 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
  • 思路

图转自acwing

以3的全排列为例

在这里插入图片描述

  • 代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    int path[10];// path 数组保存排列,当排列的长度为 n 时,是一种方案,输出
    bool st[10];//st 数组表示数字是否用过:当 st[i] 为 1 时,i 已经被用过,否则 没有被用过
    
    void dfs(int u) //dfs(u) 表示:在 path[i] 处填写数字,然后递归的在下一个 u 位置填写数字
    {
        if(u==n)
        {
            for(int i=0;i<n;i++) cout<<path[i]<<' ';  //是一种方案输出
            cout<<endl;
            return ;
        }
        
        for(int i=1;i<=n;i++)
        {
            if(!st[i])  //i 没有被使用过,现在使用
            {
                st[i]=true;  //状态 改成使用过
                path[u]=i;  //在方案中填上这个数
                dfs(u+1);  //填下一个位置上的数
                st[i]=false; //回溯:第 i 个位置填写某个数字的所有情况都遍历后, 第 i 个位置填写下一个数字
            }
        }
    }
    
    
    int main()
    {
        cin>>n;
        
        dfs(0);  //从第0个位置上,开始递归,搜索
    
        return 0;
    }
    

2.2 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..

方法一

  • 思路

    棋盘皇后这个题,和数的全排列很相似

    按行枚举,枚举的时候,就保证了行不会重复;

    开始放置棋子,第u行第i列 看看是否可以放皇后,可以就放,递归下一行 u+1

    直到最后,全部 n 个皇后放上棋盘

    图解如下图转自acwing

    在这里插入图片描述

  • 代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    const int N=20;
    char q[N][N];  //存储棋盘
    bool cor[N],dg[2*N],udg[2*N];  //cor表示每一列,dg和udg表示正对角线和反对角线,来存储他们的是否被使用过的状态 
    
    void dfs(int u)  //放第 u 行的棋子 (深度优先遍历)
    {
        if(u==n) //如果放盘,则输出棋盘
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                    cout<<q[i][j];
                cout<<endl;
            }
            
            cout<<endl;
            return ;  //重点!! 递归到最深层,返回,千万别忘记
        }
        
        for(int i=0;i<n;i++)  //从第一列,开始遍历,是否放棋
        {
            if(!col[i]&&!dg[i+u]&&!udg[n-i+u])  //如果 列,对角线,没有被放过,则放皇后
            {
                q[u][i]='Q';  //放上
                col[i]=dg[i+u]=udg[n-i+u]=true;  //改变状态,dg[i+u]表示截距,每个对角线,都有自己独有的截距;反对角线的截距是负数,数组的下标,不能存放负数,所以加上 n这个偏移量
                dfs(u+1);  //放下一行的
                col[i]=dg[i+u]=udg[n-i+u]=false;  //恢复现场
                q[u][i]='.';
            }
        }
    }
    
    
    
    int main()
    {
        cin>>n;
        
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                q[i][j]='.';  //初始化棋盘
        
        dfs(0);  //从第0行,开始放棋子
    
        return 0;
    }
    
    

方法二

  • 思路

    枚举 每一个位置的棋子

    每个位置可以分成两种情况:放Q 不放Q

    把每一种情况都枚举出来

  • 代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    const int N=20;
    char q[N][N];
    bool row[N], col[N],dg[N],udg[N];
    
    
    void dfs(int x,int y,int s) //x表示行,y表示列,s表示已经放上皇后的个数
    {
        //处理超边界地情况
        if(y==n) y=0,x++;   
        
        if(x==n)  //每个位置都枚举完了
        {
            if(s==n)  // n 个皇后都放上去了
            {
                for(int i=0;i<n;i++)
                    puts(q[i]);  //输出棋盘, q[i],传的是数组指针,输出的是一整行
                puts("");
            }
            return ;  //递归到最后返回
        }
    
        //分支1,不放皇后
        dfs(x,y+1,s);
        
        //分支2,放皇后
        if(!row[x]&&!col[y]&&!dg[x+y]&&!udg[n-x+y])
        {
            q[x][y]='Q';
            row[x]=col[y]=dg[x+y]=udg[n-x+y]=true;
            dfs(x,y+1,s+1);
            row[x]=col[y]=dg[x+y]=udg[n-x+y]=false;
            q[x][y]='.';
        }
        
    }
    
    int main()
    {
        cin>>n;
        
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                q[i][j]='.';
        
        dfs(0,0,0);
    
        return 0;
    }
    

3.BFS

比较简单,一般模板可以直接解决

直接上例题,来理解一下

3.1走迷宫

给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 00 或 11,其中 00 表示可以走的路,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
  • 思路

    从起点开始,遍历每一个位置,

    看他四个方向,是否满足条件,满足条件的,走它,

    在看它的四个方向是否满足条件,满足走它

    每走一步,距离+1,

    最后返回 走到 终点 的距离

    图解如下图转自acwing

    在这里插入图片描述

  • 代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef pair<int ,int> PII;  //定义 坐标
    
    const int N=110;
    
    int n,m;
    int g[N][N];  //表示地图
    int d[N][N];  //存的是某一点到源点的距离
    
    int dfs()
    {
        queue<PII> q;  //定义队列,里面存的表示我们将要走的哪一个点
        q.push({0,0});  //先把放进去,表示我们要走  起点
        
        memset(d,-1,sizeof d);  //初始化,把每个点到源点的距离初始化为  -1
        d[0][0]=0;  //源点到自己的距离为0
        
        int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};  //我们定义的四个方向 x,y 的移动,这样可以避免 4个判断语句,注意 dx,dy 要一一对应
        
        //从第一个开始位置开始遍历
        while(!q.empty())  //走到最后
        {
            auto t=q.front();  //把队列中的第一个元素取出来
            q.pop();  //对头元素出列
            
            for(int i=0;i<4;i++)
            {
                int x=t.first+dx[i],y=t.second+dy[i]; //扩展之后的坐标
                
                //x,y不能越界,可以走,没走过
                if(x>=0&&x<n&&y>=0&&y<m&&g[t.first][t.second]==0&&d[x][y]==-1)
                {
                    d[x][y]=d[t.first][t.second]+1;  //距离+1
                    q.push({x,y}); //把把满足条件地坐标插进去,下一次走它们
                }
            }
        }
        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<<dfs()<<endl;
        
        return 0;
    }
    

Alt

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

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

相关文章

leetcode打卡-深度优先遍历和广度优先遍历

200.岛屿数量 leetcode题目链接&#xff1a;https://leetcode.cn/problems/number-of-islands leetcode AC记录&#xff1a; 思路&#xff1a;深度优先遍历&#xff0c;从0&#xff0c;0开始遍历数组&#xff0c;使用boolean类型数组used记录是否被访问过&#xff0c;进行一…

28个案例问题分析---014课程推送页面逻辑整理--vue

一&#xff1a;背景介绍 项目开发过程中&#xff0c;前端出现以下几类问题&#xff1a; 代码结构混乱代码逻辑不清晰页面细节问题 二&#xff1a;问题分析 代码结构混乱问题 <template><top/><div style"position: absolute;top: 10px"><C…

SpringBoot监听机制-以及使用

11-SpringBoot事件监听 Java中的事件监听机制定义了以下几个角色&#xff1a; ①事件&#xff1a;Event&#xff0c;继承 java.util.EventObject 类的对象 ②事件源&#xff1a;Source &#xff0c;任意对象Object ③监听器&#xff1a;Listener&#xff0c;实现 java.util…

奇思妙想:超链接唤起本地应用

文章目录分析实现参考很多人的博客都有这样的小玩意&#xff0c;点击之后就可以直接与博主进行对话&#xff0c;而且无需添加好友。 先研究一下网页源代码&#xff1a; <a href"tencent://message/?uin88888888&Siteqq&Menuyes">联系我</a>很明…

Decoupled Knowledge Distillation(CVPR 2022)原理与代码解析

paper&#xff1a;Decoupled Knowledge Distillationcode&#xff1a;https://github.com/megvii-research/mdistiller/blob/master/mdistiller/distillers/DKD.py背景与基于响应logits-based的蒸馏方法相比&#xff0c;基于特征feature-based的蒸馏方法在各种任务上的表现更好…

【教学典型案例】14.课程推送页面整理-增加定时功能

目录一&#xff1a;背景介绍1、代码可读性差&#xff0c;结构混乱2、逻辑边界不清晰&#xff0c;封装意识缺乏![在这里插入图片描述](https://img-blog.csdnimg.cn/bbfc5f04902541db993944ced6b62793.png)3、展示效果不美观二&#xff1a;案例问题分析以及解决过程1、代码可读性…

现代操作系统——Linux架构与学习

小白的疑惑 在我决定从事嵌入式&#xff08;应用层&#xff09;方面的工作时&#xff0c;我查询了大量资料该如何学习&#xff0c;几乎所有观点不约而同的都指向了学习好Linux&#xff0c;大部分工作都是在Linux环境下来进行工作的。于是我雄心勃勃的去下载Linux&#xff0c;可…

GEE开发之降雨(CHIRPS)数据获取和分析

GEE开发之降雨CHIRPS数据获取和分析1.数据介绍2.初识CHIRPS2.1 代码一2.2 代码二3.逐日数据分析和获取4.逐月数据分析和获取4.1 代码一4.2 代码二(简洁)5.逐年数据分析和获取5.1 代码一5.2 代码二(简洁)前言&#xff1a;主要获取和分析UCSB-CHG/CHIRPS/DAILY的日数据、月数据和…

一文带你入门,领略angular风采(上)!!!

话不多说&#xff0c;上代码&#xff01;&#xff01;&#xff01; 一、脚手架创建项目 1.安装脚手架指令 npm install -g angular/cli 2.创建项目 ng new my-app(ng new 项目名) 3.功能选择 4.切换到创建好的项目上 cd my-app 5.安装依赖 npm install 6.运行项目 npm start或…

32 openEuler使用LVM管理硬盘-管理卷组

文章目录32 openEuler使用LVM管理硬盘-管理卷组32.1 创建卷组32.2 查看卷组32.3 修改卷组属性32.4 扩展卷组32.5 收缩卷组32.6 删除卷组32 openEuler使用LVM管理硬盘-管理卷组 32.1 创建卷组 可在root权限下通过vgcreate命令创建卷组。 vgcreate [option] vgname pvname ...…

曹云金郭德纲关系迎曙光,新剧《猎黑行动》被德云社弟子齐点赞

话说天下大势&#xff0c;分久必合&#xff0c;合久必分。这句话经过了历史的证明&#xff0c;如今依然感觉非常实用。 就拿郭德纲和曹云金来说&#xff0c;曾经后者是前者的得门生&#xff0c;两个人不但情同父子&#xff0c;曹云金还是郭德纲默认接班人。然而随着时间的流逝&…

数据库基本概念及常见的数据库简介

数据库基本概念 【1】数据库基本概念 &#xff08;1&#xff09;数据 所谓数据&#xff08;Data&#xff09;是指对客观事物进行描述并可以鉴别的符号&#xff0c;这些符号是可识别的、抽象的。它不仅仅指狭义上的数字&#xff0c;而是有多种表现形式&#xff1a;字母、文字…

设计模式-策略模式

前言 作为一名合格的前端开发工程师&#xff0c;全面的掌握面向对象的设计思想非常重要&#xff0c;而“设计模式”是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的&#xff0c;代表了面向对象设计思想的最佳实践。正如《HeadFirst设计模式》中说的一句话&…

【Verilog】——模块,常量,变量

目录 1.模块 1.描述电路的逻辑功能 2. 门级描述 3.模块的模板​编辑 2.关键字 3.标识符 4.Verilog源代码的编写标准 5.数据类型 1.整数常量​ 2.参数传递的两种方法 3.变量 4.reg和wire的区别 5.沿触发和电平触发的区别​ 6.memory型变脸和reg型变量的区别​ 1.模块 1.描…

Mybatis一级缓存与二级缓存

一、MyBatis 缓存缓存就是内存中的数据&#xff0c;常常来自对数据库查询结果的保存。使用缓存&#xff0c;我们可以避免频繁与数据库进行交互&#xff0c;从而提高响应速度。MyBatis 也提供了对缓存的支持&#xff0c;分为一级缓存和二级缓存&#xff0c;来看下下面这张图&…

docker安装即docker连接mysql(window)

一 安装docker 1.什么是docker Docker容器与虚拟机类似&#xff0c;但二者在原理上不同。容器是将操作系统层虚拟化&#xff0c;虚拟机则是虚拟化硬件&#xff0c;因此容器更具有便携性、高效地利用服务器。 2.WSL2 WSL&#xff0c;即Windows Subsystem on Linux&#xff0c;中…

JavaScript高级 XHR - Fetch

1. 前端数据请求方式 早期的网页都是通过后端渲染来完成的&#xff1a;服务器端渲染&#xff08;SSR&#xff0c;server side render&#xff09; 客户端发出请求 -> 服务端接收请求并返回相应HTML文档 -> 页面刷新&#xff0c;客户端加载新的HTML文档 当用户点击页面中…

C++:哈希:闭散列哈希表

哈希的概念 哈希表就是通过哈希映射&#xff0c;让key值与存储位置建立关联。比如&#xff0c;一堆整型{3,5,7,8,2,4}在哈希表的存储位置如图所示&#xff1a; 插入数据的操作&#xff1a; 在插入数据的时候&#xff0c;计算数据相应的位置并进行插入。 查找数据的操作&…

从企业数字化发展的四个阶段,看数字化创新战略

《Edge: Value-Driven Digital Transformation》一书根据信息技术与企业业务发展的关系把企业的数字化分为了四个阶段&#xff1a; 技术与业务无关技术作为服务提供者开始合作科技引领差异化优势以技术为业务核心 下图展示了这四个阶段的特点&#xff1a; 通过了解和分析各个…

[ant-design-vue] tree 组件功能使用

[ant-design-vue] tree 组件功能使用描述环境信息相关代码参数说明描述 是希望展现一个树形的菜单&#xff0c;并且对应的菜单前有复选框功能&#xff0c;但是对比官网的例子&#xff0c;我们在使用的过程中涉及到对半选中情况的处理&#xff1a; 半选中状态&#xff1a; 选中…