基础算法(9):搜索(深搜)

目录

1.深度优先搜索

2.迷宫(经典深搜)

2.1 建图

2.2 深搜与回溯

2.3 完整代码 

3.洛谷DFS

3.1 跳马

3.2 八皇后

3.2.1 建图

3.2.2 搜索

3.2.3 完整代码

3.3 Lake Counting(水坑计数)


     今天主要来了解深度优先搜索(DFS)。

1.深度优先搜索

     深搜的过程是从根节点进入,向下走,走到底再向上走,最后从根退出

     深搜是通过系统栈实现的。

     递归调用的过程,系统自动通过栈去维护函数的状态空间。

     系统栈记录函数返回地址、局部变量、参数传递等。向下走,压栈;向上走,弹栈。

     其实深搜就是枚举,暴力搜索而已。

2.迷宫(经典深搜)

     

输入
3 3 1
1 2 3 3 
2 3输出
4

     如图,起点坐标为(1,2),终点坐标为(3,3),障碍物坐标为(2,3),问我们从起点到终点有多少种走法,对于这种方案数的问题,正合DFS的口味,DFS就是通过暴力搜索、枚举所有可能的情况来找到答案,下面来看如何使用DFS:

2.1 建图

      g[x][y]存入迷宫图,并进行判重

      dx[4],dy[4]存方向偏移量,因为走到每个格子,我们又有四个方向可以走,需要枚举每个方向

      格子就是点,格子到格子就是边

int m,n,t,sx,sy,fx,fy,a,b,ans;
int g[N][N];//存图并判重
int dx[4]={-1,0,1,0};//存方向偏移量
int dy[4]={0,1,0,-1};//存方向偏移量int main()
{cin>>n>>m>>t;//输入迷宫长度和障碍物总数cin>>sx>>sy>>fx>>fy;//输入起点和终点坐标for(int i=0;i<t;i++)cin>>a>>b,g[a][b]=1;//障碍物坐标,不能走,g[a][b]=1,表示已经走过,之后不会重复搜索,0表示还没有走过g[sx][sy]=1;//起点已经走过dfs(sx,sy);//从起点开始搜索cout<<ans;//输出答案return 0;
}

2.2 深搜与回溯

     从起点开始,四个方向进行搜索,能走就进行标记,锁定现场,然后走过去;一直走到无路可走就返回或者到达目的地,更新答案后返回,返回后要去除标记,恢复现场,之后还能继续走;继续尝试,直到枚举完所有可能,最后从入口退出。

void dfs(int x,int y)
{if(x==fx&&y==fy){ans++;return;}for(int i=0;i<4;i++){int a=x+dx[i],b=y+dy[i];if(a<1||a>n||b<1||b>m)continue;//坐标超出图的范围if(g[a][b])continue;//在本次搜索中已经走过了,不再进行下一步的搜索g[a][b]=1;//锁定现场dfs(a,b);//进行进一步的搜索g[a][b]=0;//恢复现场}
}

     深搜会生成DFS树:

2.3 完整代码 

#include<iostream>
using namespace std;
const int N=10;
int m,n,t,sx,sy,fx,fy,a,b,ans;
int g[N][N];//存图并判重
int dx[4]={-1,0,1,0};//存方向偏移量
int dy[4]={0,1,0,-1};//存方向偏移量void dfs(int x,int y)
{if(x==fx&&y==fy){ans++;return;}for(int i=0;i<4;i++){int a=x+dx[i],b=y+dy[i];if(a<1||a>n||b<1||b>m)continue;//坐标超出图的范围if(g[a][b])continue;//在本次搜索中已经走过了,不再进行下一步的搜索g[a][b]=1;//锁定现场dfs(a,b);//进行进一步的搜索g[a][b]=0;//恢复现场}
}int main()
{cin>>n>>m>>t;//输入迷宫长度和障碍物总数cin>>sx>>sy>>fx>>fy;//输入起点和终点坐标for(int i=0;i<t;i++)cin>>a>>b,g[a][b]=1;//障碍物坐标,不能走,g[a][b]=1,表示已经走过,之后不会重复搜索,0表示还没有走过g[sx][sy]=1;//起点已经走过dfs(sx,sy);//从起点开始搜索cout<<ans;//输出答案return 0;
}

3.洛谷DFS

3.1 跳马

     这个题和迷宫问题没什么区别,区别在于方向偏移量不一样,马只能走日,本来有八个方向,但只能往右上角跳,所以只有四个方向,同时因为不能向左跳,所以我们不用进行锁定现场和恢复现场进行判重,一直向右就完事了。

#include<iostream>
using namespace std;
int m,n,ans;
int dx[4]={2,1,-1,-2};
int dy[4]={1,2,2,1};void dfs(int x,int y)
{if(x==n&&y==m){ans++;return;}for(int i=0;i<4;i++){int a=x+dx[i],b=y+dy[i];if(a<0||a>n||b>m)continue;dfs(a,b);}
}int main()
{cin>>n>>m;dfs(0,0);cout<<ans;return 0;
}

3.2 八皇后

     八皇后也是经典的DFS问题,也是方案数问题,以输入输出样例来看,简单来说就是每行每列每个对角线只能有一个皇后

3.2.1 建图

     pos数组记录各行放的位置。pos[1]=2

     c数组标记列。c[2]=1

     p数组标记撇对角线。p[1+2]=1 行列之和是定值(找行和列与对角线的映射关系)

     q数组标记捺对角线。q[1-2+6]=1 行列之差是定值,防止下标为负数,都加上图的长度

     p的下标(i+j) : 2,3,4,...,2n 范围

     q的下标(i-j+n):1,2,3,...2n-1 范围

int n,ans;
int pos[N],c[N],p[N],q[N];//pos存每行皇后放在第几列int main()
{cin>>n;dfs(1);cout<<ans<<endl;return 0;
}
3.2.2 搜索

     从第一行开始放,之和尝试放2-n行。

    对于第i行,依次枚举1-n列,如果第j列能放,记住该位置,记住其对角线和列,然后继续搜索第i+1行。

    如果第i+1行的n列均不能放,则退回到第i行的状态,恢复现场,尝试第i行的下一列

    如果能放满n行,说明找到了一种方案,则更新答案,返回上一行,继续搜索另一个合法方案,直到搜完所有可能方案

void print()
{if(ans<=3){for(int i=1;i<=n;i++)printf("%d ",pos[i]);puts("");}
}void dfs(int i)
{if(i>n){ans++;print();return;}for(int j=1;j<=n;j++)//枚举列{if(c[j]||p[i+j]||q[i-j+n])continue;pos[i]=j;//记录第i行放在了第j列c[j]=p[i+j]=q[i-j+n]=1;//宣布占领dfs(i+1);c[j]=p[i+j]=q[i-j+n]=0;//恢复现场}
}
3.2.3 完整代码
#include<iostream>
using namespace std;
const int N=25;
int n,ans;
int pos[N],c[N],p[N],q[N];//pos存每行皇后放在第几列void print()
{if(ans<=3){for(int i=1;i<=n;i++)printf("%d ",pos[i]);puts("");}
}void dfs(int i)
{if(i>n){ans++;print();return;}for(int j=1;j<=n;j++)//枚举列{if(c[j]||p[i+j]||q[i-j+n])continue;pos[i]=j;//记录第i行放在了第j列c[j]=p[i+j]=q[i-j+n]=1;//宣布占领dfs(i+1);c[j]=p[i+j]=q[i-j+n]=0;//恢复现场}
}
int main()
{cin>>n;dfs(1);cout<<ans<<endl;return 0;
}

3.3 Lake Counting(水坑计数)

  

     这个是DFS的另一个经典应用,连通块问题 ,如果一个网格有水,则周围的八个网格和这个网格就视为一个水坑,这个很明显也是要存方向偏移量,很明显的DFS,而且很明显是不需要回溯的,能连通就能,不能就放弃,只需要判重防止重复搜索就行了。

#include<iostream>
using namespace std;
const int N=110;
int n,m,ans;
char g[N][N];
int dx[8]={-1,-1,-1,0,1,1,1,0};
int dy[8]={-1,0,1,1,1,0,-1,-1};void dfs(int x,int y)
{g[x][y]='.';for(int i=0;i<8;i++){int a=x+dx[i],b=y+dy[i];if(a<0||a>=n||b<0||b>=m)continue;if(g[a][b]=='.')continue;dfs(a,b);}
}
int main(){cin>>n>>mfor(int i=0;i<n;i++)cin>>g[i];for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(g[i][j]=='W'){dfs(i,j);ans++;}}}cout<<ans;return 0;
}

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

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

相关文章

【网站项目】基于SSM的263货物进销管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

《WebKit 技术内幕》学习之五(2): HTML解释器和DOM 模型

2.HTML 解释器 2.1 解释过程 HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。 这一过程中&#xff0c;WebKit 内部对网页内容在各个阶段的结构表示。 WebKit 中这一过程如下&#xff1a;首先是字节流&#xff0c;经过解码之…

c/c++公交管理系统(星穹轨道可视化EasyX)

注&#xff1a;全代码由博主个人耗时两个星期开发&#xff0c;实现了基础的公交管理系统功能&#xff1a;1.前端用户查询站点以及查看所有站点。2.后端管理员权限&#xff0c;实现登录系统检验&#xff0c;添加路线以及删除路线。最重要的是使用EasyX实现了星穹轨道的启动以及抽…

Buttton样式设置background属性失效的问题

最近遇到一个之前没有遇见的问题&#xff0c;就是在添加Button控件的时候发现对其设置background时没有效果&#xff0c;原因是AndroidStudio升级后默认按钮就是主题色&#xff0c;一个比较简单的方法是将Button改为android.widget.Button&#xff0c;对比效果如下&#xff1a;…

提升认知,推荐15个面向开发者的中文播客

前言 对于科技从业者而言&#xff0c;无论是自学成才的程序员&#xff0c;还是行业资深人士&#xff0c;终身学习是很有必要的&#xff0c;尤其是在这样一个技术快速迭代更新的时代。 作为一个摆脱了时间和空间限制的资讯分享平台&#xff0c;播客&#xff08;Podcast&#x…

RK3399平台开发系列讲解(高速设备驱动篇)6.9、SD卡读写流程

🚀返回总目录 文章目录 一、SD卡相关命令介绍1.1、读操作1.2、写操作一、SD卡相关命令介绍 SD卡的读写流程中,需要使用一些特定的命令(CMD)与SD卡进行通信。以下是一些常见的SD卡命令: CMD0(GO_IDLE_STATE): 这是初始化命令,用于将SD卡置于空闲状态。CMD8(SEND_IF_…

数据库中的经纬度数据如何在QGIS中显示

思路&#xff1a;必须先将经纬度数据转换成POINT&#xff0c;MULTILINESTRING等格式才能在QGIS中展示 步骤 1、首先在postgresql数据中建一张包括经纬度数据的表 **注意&#xff1a;**如果是新建数据库&#xff0c;一定要执行如下代码&#xff0c;否则后面的函数ST_GeomFrom…

CTFhub-网站源码

CTFhub-Web-信息泄露-备份文件下载-网站源码 题目信息 解题过程 无脑爆破&#xff08;笑 写个python脚本 import requests #这里的url是你的地址 url "http://challenge-67a05a3755f2610d.sandbox.ctfhub.com:10800/"list1 [web, website, backup, back, www, ww…

VRRP6协议--主备配置

VRRP6概念 VRRP6备份组能够在不改变组网的情况下,采用将多台设备虚拟成一台网关设备,将虚拟交换机设备的IP地址作为用户的默认网关的方式实现下一跳网关的备份。配置VRRP6备份组后,流量通过Master设备转发,当Master设备故障时,迅速选举出新的Master设备继续承担流量转发,…

C++ Primer 6.5 特殊用途语言特性 6.6 函数匹配 知识点+练习题

C Primer6.5 特殊用途语言特性 6.6 函数匹配 默认实参内联函数constexpr函数调试帮助assert预处理宏NDBUG预处理变量 函数匹配练习题 默认实参 string screen(int hz24,int wid80,char c) windowscreen( , ,?)&#xff1b;//错误&#xff01;&#xff0c;只有尾部的实参可以省…

搭建一个简单的Spring Demo

要学习Spring 源码&#xff0c;一个是从Spring GitHub 上去down源码&#xff0c;然后倒入IDEA编译&#xff0c;但这种方法费时费力&#xff0c;如果你不需要对Spring 源码进行修改后&#xff0c;再编译的话&#xff0c;直接搭建一个Spring Demo 的Maven项目&#xff0c;引入Spr…

快速上手的AI工具-文心辅助学习

前言 大家好晚上好&#xff0c;现在AI技术的发展&#xff0c;它已经渗透到我们生活的各个层面。对于普通人来说&#xff0c;理解并有效利用AI技术不仅能增强个人竞争力&#xff0c;还能在日常生活中带来便利。无论是提高工作效率&#xff0c;还是优化日常任务&#xff0c;AI工…