小学四年级也能看懂的DFS(10、DFS 综合练习第4课:魔法王国的终极挑战——简化版 N 皇后)

发布时间:2026/10/23 2:58:40

小学四年级也能看懂的DFS(10、DFS 综合练习第4课:魔法王国的终极挑战——简化版 N 皇后) DFS 综合练习第四课魔法王国的终极挑战——简化版 N 皇后这一课我们把前面学过的 DFS 知识全部串起来前面三课我们已经学会了第一课枚举所有可能学会了选择。第二课金币凑数、勇士爬台阶学会了记录方案、检查结果。第三课勇闯魔法地图学会了检查条件、避免走进死胡同。今天我们要挑战一个经典的算法问题——N 皇后问题。我们先不挑战 8×8 的大棋盘而是从简单的 4×4 棋盘开始。只要弄懂这道题将来再挑战更大的棋盘就有了基础一、故事开始四位皇后的魔法棋盘魔法王国举办了一场棋盘挑战赛。棋盘有 4 行、4 列需要放置 4 位皇后并且满足一个重要规则任何两位皇后都不能互相攻击。在国际象棋中皇后可以沿着横线、竖线和斜线移动。因此两位皇后不能处于同一行、同一列或同一条斜线上。我们把规则拆成三个孩子容易理解的要求规则一不能同行每一行只能放一位皇后。规则二不能同列已经有皇后的列不能再放另一位皇后。规则三不能同斜线两位皇后如果沿着斜线相连就会发生冲突。我们的任务是找出所有合法的摆放方案并统计一共有多少种。注意这道题不是让我们随便摆四位皇后而是要把所有符合规则的方案都找出来一个也不能漏二、先不写代码我们应该怎样思考还记得前面学过的“岔路口”吗每次来到一个岔路口我们都尝试不同的选择。这一次我们不再决定“选还是不选”而是来到第几行就决定这一行的皇后放在哪一列。比如第一行有 4 个选择假设第一位皇后放在第 1 行、第 1 列。接下来轮到第二行。第二行也有四个位置可以尝试但有些位置已经不合法了。第 1 列和第一位皇后同列不行第 2 列和第一位皇后在斜线上不行第 3 列没有同行、同列或斜线冲突可以继续尝试。第 4 列也没有冲突可以继续尝试。我们只沿着合法的选择继续往下探索。如果后来发现无论怎样摆都无法完成任务就退回上一行换一个位置。这就是 DFS 在这道题里的工作方式选择一个位置 → 检查是否合法 → 记录选择 → 继续下一行如果走不通就退回来换位置。三、给电脑准备一本“皇后位置记录本”如果我们每次都把棋盘画出来电脑会不会很累其实我们只需要用一个数组就能记录每位皇后的位置。int col[5];这里使用下标1、2、3、4表示第几行数组里的数字表示皇后所在的列。例如记录本就是第几行对应第几列。例如col[2] 4的意思就是第二行的皇后放在第四列。这样我们就不必保存整个棋盘只用几个数字就能记住摆放方案。四、最重要的一步怎样检查皇后是否合法假设我们正在给第row行摆放皇后。前面几行的皇后已经摆好了我们只需要检查它和前面每一位皇后有没有冲突。检查一是不是在同一列如果col[row] col[i]就说明当前皇后和第i行的皇后在同一列发生冲突。例如第 1 行在第 2 列第 3 行也想放在第 2 列。两位皇后在同一列所以不合法。检查二是不是在同一条斜线上这是本题最关键的知识点看下面这个例子我们用一个规律判断斜线两位皇后所在行的距离等于它们所在列的距离就在同一条斜线上。例如第一位皇后在第 1 行、第 2 列第二位皇后在第 3 行、第 4 列。行号相差 3-1 2列号相差 4-2 2。两个距离相等因此在同一条斜线上不能这样摆放。代码里可以这样判断if (row - i col[row] - col[i] || row - i col[i] - col[row]) { return false; }为了让代码更简洁我们也可以使用绝对值if (row - i abs(col[row] - col[i])) { return false; }这里的abs()是求绝对值。例如abs(-2)的结果是2。五、把 DFS 的五个动作串起来这道题里DFS 不再是一个陌生的东西而是我们熟悉的“岔路口探险”。其中剪枝可以理解为发现这条路已经不可能成功就不再浪费时间继续走。例如某位皇后已经和前面的皇后在同一列了就没必要再摆后面的皇后了。我们直接放弃这个选择换下一列。六、完整 C 参考程序接下来我们把刚才的想法变成代码。建议同学们自己先猜一猜每个函数负责什么再一起阅读。#include iostream #include cstdlib using namespace std; const int N 4; // col[row] 表示第 row 行的皇后所在的列 int col[N 1]; int cnt 0; // 检查当前行的皇后是否合法 bool check(int row) { for (int i 1; i row; i) { // 检查是否在同一列 if (col[row] col[i]) { return false; } // 检查是否在同一条斜线上 if (row - i abs(col[row] - col[i])) { return false; } } return true; } // 从第 row 行开始摆放皇后 void dfs(int row) { // 四行都摆好了找到一种完整方案 if (row N 1) { cnt; cout 方案 cnt ; for (int i 1; i N; i) { cout col[i] ; } cout endl; // 打印棋盘 for (int i 1; i N; i) { for (int j 1; j N; j) { if (col[i] j) { cout Q ; } else { cout . ; } } cout endl; } cout endl; return; } // 尝试把皇后放在当前行的每一列 for (int c 1; c N; c) { // 选择并记录位置 col[row] c; // 检查合法合法才继续搜索 if (check(row)) { dfs(row 1); } // 恢复记录尝试下一列 col[row] 0; } } int main() { dfs(1); cout 一共找到 cnt 种方案 endl; return 0; }七、逐步追踪电脑是怎样找到第一种方案的先看程序最开始的调用dfs(1);意思是从第一行开始摆放皇后。我们用一张表跟着电脑走一遍。当前行尝试位置检查结果下一步第 1 行第 1 列合法进入第 2 行第 2 行第 1 列同列冲突剪枝第 2 行第 2 列斜线冲突剪枝第 2 行第 3 列合法进入第 3 行第 3 行逐列尝试都无法完成返回第 2 行第 2 行第 4 列合法重新探索第 3 行这说明了一个重要道理第一行放在第 1 列并不代表后面一定有解。如果这一条路走不通DFS 就会回到前面的岔路口换一个选择。它不会因为前面已经花了时间就死守错误的方案。最终程序会找到两种合法方案。程序的主要输出如下方案 12 4 1 3 . Q . . . . . Q Q . . . . . Q . 方案 23 1 4 2 . . Q . Q . . . . . . Q . Q . . 一共找到 2 种方案这里用Q表示皇后用.表示空格。注意程序输出的是两种不同的合法摆法不是只找到两位皇后。八、最后把五个知识点讲透1. 选择for (int c 1; c N; c)每一行都尝试第 1、2、3、4 列。这就是 DFS 的岔路口。2. 记录col[row] c把当前皇后的位置记下来后面的皇后才能根据它检查冲突。3. 检查check(row)检查同列和同斜线。每次只需要检查当前皇后与前面几行的皇后。4. 剪枝if (check(row))只有合法的选择才能进入下一行。不合法的选择直接放弃不继续搜索。5. 恢复col[row] 0当前选择探索完毕后清除这一行的记录接着尝试下一列。否则之前的选择可能会影响后面的探索。九、课后练习试着自己当一回 DFS 探险家练习一理解数组如果col[3] 4代表什么A、第三列放了第四位皇后B、第三行的皇后放在第四列C、第四行的皇后放在第三列答案B。col[3] 表示第三行的皇后所在列。练习二理解剪枝如果当前皇后与前面某位皇后在同一列应该怎么办继续摆下一行把已经摆好的皇后全部删除放弃当前列尝试下一列答案C。当前选择不合法就放弃它尝试下一列。练习三理解恢复为什么尝试完一个位置后要执行col[row] 0清除当前行的旧记录方便尝试其他位置让程序马上结束把皇后移动到第 0 列答案A。恢复记录避免旧选择干扰后面的探索。十、这一课的记忆口诀每行选一列先记再检查合法往下走不合法就剪枝走完要恢复找到答案就记录。这就是 DFS 综合运用的完整过程。从子集、排列、组合到金币凑数、爬台阶再到网格、迷宫和 N 皇后我们一直在做同一件事尝试选择记录状态检查条件继续探索走不通就返回。同学们真正掌握了这个思路以后遇到新的搜索题就不只是背代码而是能够自己分析有哪些选择怎样判断合法什么时候继续什么时候返回这才是学习 DFS 最重要的收获。
延伸阅读

更多相关文章

2026/10/23 2:58:40

量子哲学的人生实质| 赵杰 | 量子哲学

作者:赵杰清华大学硕士、微美全息云科技(NASDAQ:WIMI)董事长、微算法科技(NASDAQ:MLGO)董事长、育杰奖学金创始人整套体系以爱子为唯一底层通用单元,以意识结构性错误为人类认知遮蔽…

2026/10/23 2:58:40

AI产品小白必看:找准方向,轻松入门大模型

文章指出AI产品经理并非单一岗位,而是分为应用层、模型层和基建层三个方向。应用层侧重场景和交互,模型层关注模型选型和调优,基建层负责部署与成本控制。作者强调应根据个人背景和职业目标选择主攻方向,并理解其他方向的基础知识…

2026/10/23 4:03:51

MATLAB常见问题30秒速查与高效排障指南

1. MATLAB高效排障指南:30秒解决常见问题作为一名MATLAB老用户,我深知在科研和工程计算中,那些突如其来的报错信息有多让人头疼。记得刚接触MATLAB时,一个简单的矩阵维度不匹配就能让我折腾半天。经过多年实战,我总结出…

2026/10/23 4:03:51

libva中的DRM模块

主要内容 本文主要就libva中的DRM的流程进行简单说明,libva版本为libva-2.11.0(版本号为1.11.0),Digital Rights Management(DRM)指的是数字版权管理,用以保护具有版权的数字产品,包括视频,音乐,电子书等等…

2026/10/23 4:03:51

Java:54-Linux概述

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 4:03:50

linux软连接和硬链接

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 3:58:50

LangGraph+MCP实战:构建AI-SPC智能根因分析系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/23 0:02:26

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

2026/10/23 0:02:26

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

2026/10/23 0:02:26

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑