16-DFS(深度优先搜索算法)

2023-11-16

 DFS(深度优先算法)是常见的搜索算法,早期常用于需要搜索的地方,并且还拓展出很多其它算法。

深度优先算法(DFS)

DFS深度优先算法)是早期开发爬虫时常用的算法,它的搜索思路是从树根开始一直找直到找到树型数据结构的叶节点。以搜索一个节点数据为例,DFS算法会从树根开始,沿着一条路一直找到某个叶节点,如果还是找不到,它会回溯到上一个分支,沿着上一个分支节点又向下,直到找到下一个叶节点,如此往复,直至从最后一个叶节点返回到根节点。

由于DFS算法是一种灵活的算法,所以还是举个常用的例子来说明这个算法。 

八皇后问题

八皇后问题指的是将八个皇后棋子放到一个棋盘中,使得任意两个棋子不在同一横线、同一竖线、同一对角线和同一反对角线上。

下面我们来看一下如何用代码求解这个问题:

我们不妨将这个问题抽象出来,由于满足条件的排法所有的棋子一定会不同行,所以我们将这个问题看成是在8行里面每一行中任意一个格子放置一个棋子,然后再在其中选出排列出合适的情况。那么我们排列的过程就如下图所示:

那么我们可以利用一个树型的结构来描述这个问题,假设我们有一个二维数组,二维数组和棋盘位置对应,那么我们每次往棋盘里面填棋子的过程可以看成是往该二维数组里面特定位置填充元素的过程。填充的过程可以理解为从树根到树叶的一次搜索过程:

要想实现这个过程,我们首先需要一个二维数组,我们先创建该二维数组,然后在里面填入字符'o'代表初始时为空,并且设置一个输入n代表要开辟的棋盘的格数,这里的N表示上限:

#include<iostream>
using namespace std;

const int N = 20;
int n;
char chessboard[N][N];

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			chessboard[i][j] = 'o';
	}
	return 0;
}

 因为我们需要判断是否有处于同一列或者同一反对角线、同一对角线的元素,所以我们需要开辟三个数组:

bool col[N], diagonal[N], back_diagonal[N];

这些数组每个元素类型都是bool类型,数组的下标和对应的对角线如下:

之后我们就可以着手写DFS搜索算法了:

我们的DFS是一个使用递归的算法。它会自动帮我们从根节点开始往下创建节点这也是在逐步填棋子。

我们首先来看for循环,这个循环就是往下创建节点的核心,for循环每一层循环是在第u行从左到右移动格子的情况,里面的DFS递归是从上一行到下一行,所以递归每次u=u+1就代表向下移动一行。

void DFS(int u)
{
	for (int i = 0; i < n; i++)
	{
		chessboard[u][i] = 'Q';
		DFS(u + 1);
	}
}

为了判断当前的棋子是否和之前的棋子位置冲突了,我们就需要对三个布尔数组进行设置:当一个棋子放到某个位置时,这个位置对应的一列、对角线、反对角线的位置都被视作为true,表示以后棋子不能放到这个位置。

如果中间一个棋子放到这个位置,那么这个位置下面的情况都将不会被考虑,这种情况不符合if条件,代码会进行回溯,也就是说这条路就不会找到叶节点的位置,而会回溯到上一个节点的位置,并且重新向下找,这个过程就是“剪枝

void DFS(int u)
{

	for (int i = 0; i < n; i++)
	{
		if (!col[i] && !diagonal[u + i] && !back_diagonal[n - u + i-1])
		{
			chessboard[u][i] = 'Q';
			col[i] = diagonal[u + i] = back_diagonal[n - u + i-1] = true;
			DFS(u + 1);
			col[i] = diagonal[u + i] = back_diagonal[n - u + i-1] = false;
			chessboard[u][i] = 'o';
		}
	}
}

因为该程序设置的是如果中途不符合条件的路径会被剪掉,所以走到最后(u==n)的情况都是符合条件的。故我们将其打印出来输出。下图是代码执行过程的一部分:

所以总的代码如下:

#include<iostream>
using namespace std;

const int N = 20;
int n;
char chessboard[N][N];
bool col[N], diagonal[N], back_diagonal[N];

void DFS(int u)
{
	if (u == n)
	{
		for (int i = 0; i < n; i++) cout << chessboard[i]<<endl;
		cout <<endl;
		return;
	}
	for (int i = 0; i < n; i++)
	{
		if (!col[i] && !diagonal[u + i] && !back_diagonal[n - u + i-1])
		{
			chessboard[u][i] = 'Q';
			col[i] = diagonal[u + i] = back_diagonal[n - u + i-1] = true;
			DFS(u + 1);
			col[i] = diagonal[u + i] = back_diagonal[n - u + i-1] = false;
			chessboard[u][i] = 'o';
		}
	}
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			chessboard[i][j] = 'o';
	}
	DFS(0);
	return 0;
}

排列组合问题

提及DFS算法那必然需要提一下排列组合问题,这个问题和DFS算法的原理有密切的关系。我们知道,DFS算法是从树根开始向叶节点寻找,再从一个叶节点回溯到上一个节点再去找下一个节点的叶节点的动作。这种操作和我们求数字的排列原理很相似。如果我们将每搜索一个节点就理解为放一个数进去排列,那么一遍遍地搜索就是一次次地排列组合,下面是实现的代码。

#include<iostream>

using namespace std;

const int N = 10;
int n;
int arr[N];
bool flag[N];

void DFS(int u)
{
	if (u == n)
	{
		for (int i = 0; i < n; i++)
			cout << arr[i];
		cout << endl;
	}
	for (int i = 0; i < n; i++)
	{
		if (!flag[i])
		{
			arr[u] = i;
			flag[i] = true;
			DFS(u + 1);
			flag[i] = false;
		}
	}
}


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

16-DFS(深度优先搜索算法) 的相关文章

随机推荐

  • IPSEC VPN知识点总结

    具体的实验 使用IPSEC VPN实现隧道通信 使用IPSEC VPN在有防火墙和NAT地址转换的场景下实现隧道通信 DS VPN实验 目录 1 什么是数据认证 有什么作用 有哪些实现的技术手段 2 什么是身份认证 有什么作用 有哪些实现的
  • iOS 设置项目的version和build号

    设置项目的version和build号 Version 1 0 1 Build 1 0 1 1 Version是显示对外的版本号 itunesconect和Appstore用户可以看到 对应O C中获取version的值 NSBundle
  • Servlet 中 session 的创建、销毁及监听

    1 session 和 cookie 关于session和cookie详细的内在机制和区别 请另行查阅资料 可参看 Session机制详解 当客户端首次请求session对象时候 服务器会为其创建一个session 并计算出具有唯一性的se
  • Ceph—报错锦集(mgr2、pgs、mgr依赖缺失等)

    Ceph 手动部署Ceph报错锦集 mgr2 pgs mgr依赖缺失等 报错锦集 1 执行 do cmake sh时的报错提示 2 do cmake sh 的note 3 导入一些链接库 4 No module named ceph mgr
  • Android Studio编译报错:sdk:minSdkVersion 1 cannot be smaller than version 7 declared in library

    背景 有一个以前的项目从Eclipse迁移到Android Studio 结果编译的时候报错如下 Error Execution failed for task lDrawer processDebugAndroidTestManifest
  • ListView动态加载数据

    当listview需要加载的数据过多时 若一次性载入则速度会相当缓慢 影响用户体验 这时候就需要动态加载数据 即每次载入固定长度的数据 android market的listview就是采用这种方式 使得加载看起来很平滑 响应速度很快 有助
  • 物联网的四种计算类型

    简介 从一个实践者的角度来看 我经常看到计算更加可用和分布的必要性 当我开始将物联网与OT和IT系统集成时 我面临的第一个问题是设备发送到我们服务器的数据量太大 我在一个工厂自动化场景中工作 我们集成了400个传感器 这些传感器每1秒发送3
  • Qt内存管理(三) Qt的智能指针

    智能指针则可以在退出作用域时 不管是正常流程离开或是因异常离开 总调用delete来析构在堆上动态分配的对象 Qt常用的智能指针有QPointer QScopedPointer QSharedPointer 关于这几个智能指针 网上的博客基
  • 每天一个linux命令(30): chown命令

    chown将指定文件的拥有者改为指定的用户或组 用户可以是用户名或者用户ID 组可以是组名或者组ID 文件是以空格分开的要改变权限的文件列表 支持通配符 系统管理员经常使用chown命令 在将文件拷贝到另一个用户的名录下之后 让用户拥有使用
  • 双系统卸载Linux,重装Deepin

    卸载掉之前的Linux系统 参考资料 https www bilibili com video av209430195 下载diskgenius https www diskgenius cn download php 删除Linux分区
  • StackExchange.Redis Timeout performing 超时问题

    最近在做的一个项目 用的 net core 2 1 然后缓存用的Redis 缓存相关封装是同事写的 用的驱动是StackExchange Redis version 2 0 571 一直听说这个驱动并发情况下有TimeOut bug 项目开
  • Flutter--Button浅谈

    作为一个常用到不能再常用的组件 material库中的button组件都有一点奇怪 存在无法设置的内外边距 我们做一个简单的展示 选几个常见button 统一使用Text做child 外加一个带红色的Container组件 观察margin
  • JavaScript-1-100之间整数的和

    要求 求1 100之间整数的和 实现代码
  • 图像数据库

    ImageNet ImageNet是一个计算机视觉系统识别项目 是目前世界上图像识别最大的数据库 是美国斯坦福的计算机科学家李飞飞模拟人类的识别系统建立的 能够从图片识别物体 目前已经包含14197122张图像 是已知的最大的图像数据库 每
  • $(this).parent("tr").find("td").eq(0).text()

    this parent tr find td eq 0 text
  • 新年新气象---多数据源配置

    概述 2022年第一天 在这祝大家新年快乐 好运连连 事业爱情双丰收 本文主要是通过注解结合aop的方式实现多数据源的动态切换 一 配置文件 spring datasource type com alibaba druid pool Dru
  • 增强现实-实验一

    实验一 1 手工制作一个空间增强现实盒子 如示例所示 放置在平板或手机屏幕上 搭配应用实现立体投影效果 2 制作立体投影所需的视频 程序 unity 全息投影 伪 视频 盒子蛮好做的主要是视频 之前没接触过unity 研究了一番 首先设置四
  • 关于js操作cookie

    一 什么是cookie 我们在浏览器中 经常涉及到数据的交换 比如你登录邮箱 登录一个页面 我们经常会在此时设置30天内记住我 或者自动登录选项 那么它们是怎么记录信息的呢 答案就是今天的主角cookie了 Cookie是由HTTP服务器设
  • 修饰符-访问修饰符internal sealed

    摘自 internal C 参考 摘自 sealed C 参考 Internal 访问仅限于当前程序集 protected internal 访问限制到当前程序集或从包含派生的类型的类别 程序集就是代码编译后bin目录下生产的 exe或者
  • 16-DFS(深度优先搜索算法)

    DFS 深度优先算法 是常见的搜索算法 早期常用于需要搜索的地方 并且还拓展出很多其它算法 深度优先算法 DFS DFS 深度优先算法 是早期开发爬虫时常用的算法 它的搜索思路是从树根开始一直找直到找到树型数据结构的叶节点 以搜索一个节点数