搜索算法讲解

深度优先搜索-DFS

P1219 [USACO1.5] 八皇后 Checker Challenge

一个如下的 6×66 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2461352\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 iii 个数字表示在第 iii 行的相应位置有一个棋子,如下:

行号 1234561\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6

列号 2461352\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 333 个解。最后一行是解的总个数。

思路

首先思考暴力枚举解法,注意到每一行只能放一个,那就可以一行一行枚举,然后判断是否合法即可。

然后会发现暴力枚举中有很多不必要的操作,比如说我们枚举到第3行把棋子放在第3列,发现这个位置是非法的,难么其实我们就没有必要再往下面的层去枚举了,应该直接把第3行的棋子放到后面的列继续枚举即可。

总结一下现在的方法:就是一行一行的放棋子,如果在该行放置的棋子是合法的,就继续放下一行的;如果枚举是非法的,就不用继续枚举下一行了,而是更换当前行的棋子。

这种方式称为回溯算法,我们这里使用深度优先搜索来实现。

DFS板子

void dfs(int k) { // k代表递归层数,或者说要填第几个空if (所有空已经填完了) {// 判断最优解 / 记录答案return;}for (枚举这个空能填的选项) {if (这个选项是合法的) {占位dfs(k + 1) // 下一层递归取消占位}}
}

接下来还有个难点,就是如何判断选项合法。首先行上一定不会冲突,因为我们是一行一行枚举的,每行只能放一个;然后列的话我们可以创建一个名如used_col的bool列表(当然int列表也可以)去存每一行的使用状态,为true就是用过了,就不能再该行再次使用,false就是没用过,就可以在该行使用;然后对角线就比较麻烦,而且对角线有两种,一种是从左往右上升,一种是从左往右下降的,都要判断清楚。

我们可以发现,从左往右上升的对角线上的点有一个特点,就是x+y的值都一样,并且除了该对角线上的点都一定不满足这个条件;另一种对角线则是x-y的值都一样。这样我们就可以开2个数组去记录对角线的使用状态,首先看x+y为定值的对角线,我们就只需要用数组记录这个定值对应的使用情况即可,就是开一个bool数组,定值对应数组下标即可;然后看x-y为定值的对角线,思路和前者相同,但是要注意定值可能为负数,就不能作为数组下标,那么就给定值加上一个较大(比x-y的最小值的绝对值大)的固定的整数再作为数组下标即可。

image-20250703222720691

解题代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N = 100;LL n, ans = 0;
LL arr[N], used_col[N], used_1[N], used_2[N]; void dfs(int k) {if (k > n) {ans++;if (ans <= 3) {for (LL i = 1; i <= n; i++) cout << arr[i] << " ";cout << endl;}return;	}for (LL i = 1; i <= n; i++) {if (!used_col[i] && !used_1[k + i] && !used_2[k - i + 20]) {arr[k] = i, used_col[i] = 1, used_1[k + i] = 1, used_2[k - i + 20] = 1; // 占位dfs(k + 1); // 递归下一层used_col[i] = 0, used_1[k + i] = 0, used_2[k - i + 20] = 0; // 取消占位}}
}int main() {cin >> n;dfs(1);cout << ans;return 0;
}

广度优先搜索-BFS

深度优先搜索会优先考虑搜索的深度。形象点说,就是不找到一个答案不回头。当答案在整棵解答树中比较稀疏时,深度优先搜索可能会先陷人过深的情况,一时半会儿找不到解。有时候需要解决连通性、最短路问题时,可以考虑使用广度优先搜索。

P1443 马的遍历

有一个 n×mn \times mn×m 的棋盘,在某个点 (x,y)(x, y)(x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

思路

这题拿dfs做的话很难写,因为他没有一层一层的体现。这道题适合的方法是bfs。

广度优先搜索会优先考虑每种状态的和初始状态的距离,形象点说,与初始状态越接近的情况会优先考虑。再具体一点:每个时刻要做的事情就是从上个时刻每个状态扩展出新的状态。

(开始在图上模拟)

当输入是 4 4 1 1时,扩展方向如图(a)。

image-20250704000140254

广度优先搜索使用队列实现:先将初始状态加人到空的队列中,然后每次取出队首,找出队首所能转移到的状态,再将其压入队列;如此反复,直到队列为空。这样就能保证一个状态在被访问的时候一定是采用的最短路径。

当输入是4 4 1 1时,队列变化如图(b)。

BFS板子

Q.push(初始状态); // 将初始状态入队
while (!Q.empty()) {State u = Q.front(); // 取出队首Q.pop(); // 出队for (枚举所有可扩展状态) // 找到u的所有可达状态vif (是合法的) // v需要满足某些条件,如未访问过、未在队内等Q.push(v); // 入队(同时可能需要维护某些信息)}

就本题而言,先建立一个结构体数组用于存储扩展的结点。先让起点人队,然后在队列取状态逐个扩展。容易被证明每个点被扩展到时一定是最少步数,这里对应了上面说的与初始状态越接近的情况会优先考虑。又因为每个点只被扩展了一次,所以以复合度是O(mn)。

解题代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;struct coord {int x, y;
};queue<coord> Q; LL n, m, x, y, ans[410][410];
LL movee[8][2] = {{2, 1}, {-2, -1}, {1, 2}, {-1, -2}, {2, -1}, {-2, 1}, {-1, 2}, {1, -2}};int main() {memset(ans, -1, sizeof(ans));cin >> n >> m >> x >> y;ans[x][y] = 0;Q.push((coord){x, y});while (!Q.empty()) {coord u = Q.front();LL x = u.x, y = u.y;Q.pop();for (LL i = 0; i < 8; i++) {LL xx = x + movee[i][0], yy = y + movee[i][1];if (xx < 1 || xx > n || yy < 1 || yy > m || ans[xx][yy] != -1) continue;Q.push((coord){xx, yy});ans[xx][yy] = ans[x][y] + 1;}}for (LL i = 1; i <= n; i++, puts("")) {for (LL j = 1; j <= m; j++) {cout << ans[i][j] << " ";}}return 0;
}

总结

对于同一个模型,无论使用dfs还是bfs,其解答树是一样的,只是搜索顺序不一样。所以通常能用dfs写的都能用bfs写,反之也可以,只是写起来的复杂程度可能不一。

同样是寻找目标解,dfs寻找操作步骤字典序最小的解,而bfs可以找到步骤最小的解。需要根据题目的性质来决定使用什么搜索算法。

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

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

相关文章

深度学习---Rnn-文本分类

# 导入PyTorch核心库 import torch # 导入神经网络模块 import torch.nn as nn # 导入优化器模块 import torch.optim as optim # 导入函数式API模块 import torch.nn.functional as F # 导入数据集和数据加载器 from torch.utils.data import Dataset, DataLoader # 导入NumPy…

20250709解决KickPi的K7开发板rk3576-android14.0-20250217.tar.gz编译之后刷机启动不了

【整体替换】 Z:\20250704\rk3576-android14.0\rkbin清理编译的临时结果&#xff1a; rootrootrootroot-X99-Turbo:~$ cd 14TB/versions/rk3576-android14.0-20250217k7/ rootrootrootroot-X99-Turbo:~/14TB/versions/rk3576-android14.0-20250217k7$ ll rootrootrootroot-X99-…

怎么创建新的vue项目

首先&#xff0c;新建一个文件点文件路径&#xff0c;输入cmd

CIU32L051系列 DMA串口无阻塞性收发的实现

1.CIU32L051 DMA的通道映射由于华大CIU32L051的DMA外设资源有限&#xff0c;DMA只有两个通道可供使用&#xff0c;对应的通道映射图如下&#xff1a;2.UART对应的引脚分布及其复用映射CIU32L051对应的UART对应的引脚映射图如下,这里博主为了各位方便查找&#xff0c;就直接全拿…

飞算 JavaAI 体验:重塑 Java 开发的智能新范式

飞算 JavaAI 体验&#xff1a;重塑 Java 开发的智能新范式引言&#xff1a;正文&#xff1a;一、工程化代码生成&#xff1a;从 "片段拼接" 到 "模块交付"1.1 传统工具的局限与突破1.2 代码质量验证二、智能重构引擎&#xff1a;从 "问题修复" 到…

深入理解JVM的垃圾收集(GC)机制

引言首先我们来介绍垃圾收集的概念&#xff0c;什么是垃圾收集&#xff1f;垃圾收集 &#xff08;Garbage Collection&#xff0c;GC&#xff09;&#xff0c;顾名思义就是释放垃圾占用的空间&#xff0c;防止内存爆掉。有效的使用可以使用的内存&#xff0c;对内存堆中已经死亡…

【笔记】国标-机动车辆及挂车分类

源于&#xff1a;GB/T 15089-2001机动车辆及挂车分类 1.L类&#xff1a;两轮或三轮车辆2.M类&#xff1a;四轮载客车辆3.N类&#xff1a;四轮载货车辆4.O类&#xff1a;挂车5.G类&#xff1a;其他

VLLM部署DeepSeek-LLM-7B-Chat 模型

一、部署环境准备1. 基础环境要求操作系统&#xff1a;Linux&#xff08;推荐欧拉系统、Ubuntu 等&#xff09;Python 版本&#xff1a;3.8 及以上依赖工具&#xff1a;pip、git、curl可选依赖&#xff1a;GPU 环境&#xff1a;NVIDIA GPU&#xff08;支持 CUDA 11.7&#xff0…

翱翔的智慧之翼:Deepoc具身智能如何赋能巡检无人机“读懂”工业现场

翱翔的智慧之翼&#xff1a;Deepoc具身智能如何赋能巡检无人机“读懂”工业现场在百米高的风力发电机叶片顶端&#xff0c;在蜿蜒数十公里的高压输电线旁&#xff0c;在油气管道穿越的崇山峻岭之上&#xff0c;一架四旋翼无人机正精准地悬停着&#xff0c;它的“眼睛”&#xf…

Java大厂面试实录:谢飞机的电商场景技术问答(Spring Cloud、MyBatis、Redis、Kafka、AI等)

Java大厂面试实录&#xff1a;谢飞机的电商场景技术问答&#xff08;Spring Cloud、MyBatis、Redis、Kafka、AI等&#xff09;本文模拟知名互联网大厂Java后端岗位面试流程&#xff0c;以电商业务为主线&#xff0c;由严肃面试官与“水货”程序员谢飞机展开有趣的对话&#xff…

Kotlin基础

前言 Decrement&#xff08;递减&#xff09; → 将一个值减 1 的操作 Predicate&#xff08;谓词&#xff09; → 返回布尔值&#xff08;逻辑值&#xff09;的函数 Reference&#xff08;引用&#xff09; → 允许使用自定义名称与对象交互 Runtime&#xff08;运行时&…

预防DNS 解析器安全威胁

DNS 是互联网的重要基础&#xff0c;例如 Web 访问、email 服务在内的众多网络服务都和 DNS 息息相关&#xff0c;DNS 的安全则直接关系到整个互联网应用能否正常使用。 DNS 解析器的作用是将用户输入的域名转换为对应的 IP 地址&#xff0c;以便计算机能够准确地定位并连接到…

Windows下VScode配置FFmpeg开发环境保姆级教程

相关准备 提前在本地开发环境中配置好mingw64或者msys2开发工具集。 安装VScode软件。 下载Windows版本的FFmpeg相关库 下载地址&#xff1a;https://ffmpeg.org/download.html 下载步骤&#xff1a;如下图。 下载后的文件&#xff1a;包含了可执行文件ffmpeg、ffpl…

Lecture #19 : Multi-Version Concurrency Control

CMU15445课程笔记多版本并发控制 多版本并发控制讲的是Mvcc。 即维护单个逻辑对象的多个物理版本&#xff0c; 这样当一个事务读取某个对象的时候不会阻塞其他事务写入该对象&#xff1b; 反之亦然。 但是Mvcc不保护写写冲突&#xff0c; 对于这种情况&#xff0c; 可能需要其两…

imx6ul Qt运行qml报错This plugin does not support createPlatformOpenGLContext!

imx6ul运行qml的Qt程序报错This plugin does not support createPlatformOpenGLContext!1、开发环境2、问题复现3、解决办法第一种方法第二种方法4、结论1、开发环境 主板&#xff1a;imx6ul Qt版本&#xff1a;5.9.6 文件系统&#xff1a;buildroot 问题描述&#xff1a;现需…

软考中项系统集成第 5 章:软件工程全流程考点拆解,备考逻辑清晰

备考系统集成项目管理工程师的小伙伴们&#xff0c;福利来啦&#xff01;今天开始为大家带来《系统集成项目管理工程师&#xff08;第 3 版&#xff09;》考点的思维导图&#xff0c;今天带来的是第5章。第 5 章聚焦软件工程&#xff0c;涵盖软件工程定义、软件需求、软件设计、…

ICLR 2025 | InterpGN:时间序列分类的透明革命,Shapelet+DNN双引擎驱动!

在Rensselaer理工学院、Stony Brook大学与IBM Research的合作下&#xff0c;本文聚焦于如何在时间序列分类任务中兼顾性能与可解释性。传统深度学习模型虽然准确率高&#xff0c;却常被诟病为“黑盒”&#xff0c;难以赢得如医疗等高风险领域的信任。为此&#xff0c;作者提出了…

使用ENO将您的JSON对象生成HTML显示

ENO 是简单易用&#xff0c;性能卓越&#xff0c;自由灵活开源的 WEB 前端组件&#xff1b;实现 JSON 与 HTML 互操作的 JavaScript 函数库。没有任何其它依赖&#xff0c;足够轻量。 WEBPack NPM 工程安装。 npm install joyzl/eno 然后在JS中引用 import "joyzl/eno…

7.12 卷积 | 最小生成树 prim

lc1900.模拟比赛算出两个指定选手最早和最晚能在第几轮碰到。还是建议dfs捏模拟比赛&#xff0c;找出两个特定选手&#xff08;firstPlayer和secondPlayer&#xff09;最早和最晚相遇的轮次。1. 定义了一个“选手”结构体&#xff0c;包含两个属性a&#xff08;战斗力&#xff…

LVS-NAT模式配置

目录 1、负载调度器配置 配置IP地址 安装ipvsadm 开启路由转发功能 加载ip_vs模块 启动ipvsadm服务 配置负载分配策略 查看验证 2、web节点配置 3、测试 1、负载调度器配置 配置IP地址 增加一块网卡 cd /etc/sysconfig/network-scripts/ cp ifcfg-ens192 ifcfg-ens…