深入浅出深度优先搜索(DFS)——以经典N皇后问题为例
创作时间:
作者:
@小白创作中心
深入浅出深度优先搜索(DFS)——以经典N皇后问题为例
引用
CSDN
1.
https://blog.csdn.net/qqqqqwerttwtwe/article/details/145501926
深度优先搜索(DFS)是一种重要的算法思想,在许多领域都有广泛的应用。本文通过经典的N皇后问题,深入浅出地介绍了DFS的核心思想、实现框架、时间空间复杂度分析,并给出了详细的代码实现和优化建议。
引言:当算法遇见棋盘
想象你面前有一张8 ∗ 8 8 * 88∗8的国际象棋棋盘,现在需要摆放8 88个皇后,使得任意两个皇后都无法互相攻击。这个看似简单的谜题,自1848 18481848年被提出以来吸引了无数数学家与计算机科学家的目光。当我们把棋盘扩展到N ∗ N N*NN∗N规格时,就诞生了著名的N皇后问题。本文将带您通过这个经典问题,深入理解深度优先搜索(DFS)这一重要的算法思想。
一、深度优先搜索原理剖析
1.1 算法核心思想
深度优先搜索(Depth-First Search)采用"不撞南墙不回头"的策略,其运行过程就像探险者深入洞穴:
- 选择一条路径走到尽头
- 遇到死胡同后回退到最近分叉点
- 尝试其他未探索的分支
- 重复直到找到解或遍历所有可能
1.2 算法实现框架
def dfs(当前状态):
if 到达终止条件:
记录/处理结果
return
for 所有可能的选择:
if 选择合法:
做出选择
dfs(新状态)
撤销选择
1.3 算法特性分析
- 时间复杂度:O ( b d ) O(b^d)O(bd)(b为分支因子,d为最大深度)
- 空间复杂度:O ( d ) O(d)O(d)(递归栈深度)
- 优势:实现简单,适合寻找所有解
- 局限:可能陷入深度路径效率低下
二、N皇后问题建模
2.1 问题描述
在N ∗ N N*NN∗N的棋盘上放置N NN个皇后,要求:
- 每行恰好一个皇后
- 每列最多一个皇后
- 每条对角线最多一个皇后
2.2 问题转化
将棋盘建模为状态空间树:
- 树节点:已放置k kk个皇后的部分解
- 树边:在第k + 1 k+1k+1行放置皇后的选择
- 叶子节点:有效解或冲突状态
三、DFS解法的实现
ACWing N皇后问题
3.1 关键数据结构
#include <iostream>
using namespace std;
const int MAX_N = 10; // 最大棋盘尺寸
int board[MAX_N][MAX_N] = {0}; // 棋盘状态,0表示空,1表示皇后
int col_used[MAX_N] = {0}; // 列占用标记
// 打印当前棋盘状态
void print_board(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << (board[i][j] ? "Q" : ".");
}
cout << endl;
}
cout << endl;
}
// 检查当前位置(x,y)是否安全
bool is_safe(int x, int y, int n) {
// 检查两条对角线
for (int i = 1; i < x; i++) {
// 左上到右下对角线
if (y - x + i > 0 && board[i][y - x + i]) return false;
// 右上到左下对角线
if (y + x - i <= n && board[i][y + x - i]) return false;
}
return true;
}
// 递归求解N皇后问题
void find_queen(int row, int placed, int n) {
// 找到一组解
if (placed == n) {
print_board(n);
return;
}
// 尝试在当前行的每一列放置皇后
for (int col = 1; col <= n; col++) {
// 跳过已被占用的列
if (col_used[col]) continue;
// 检查对角线是否安全
if (!is_safe(row, col, n)) continue;
// 放置皇后
board[row][col] = 1;
col_used[col] = 1;
// 递归处理下一行
find_queen(row + 1, placed + 1, n);
// 回溯:移除皇后
board[row][col] = 0;
col_used[col] = 0;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
// 参数说明:
// 1: 从第1行开始
// 0: 当前已放置0个皇后
// n: 棋盘大小
find_queen(1, 0, n);
return 0;
}
3.2 核心优化技巧
- 状态压缩:使用三个布尔数组分别记录列和两个对角线的占用情况
- 即时剪枝:在放置每个皇后时立即检测冲突,避免无效搜索
- 对称性优化:利用棋盘的对称性减少重复计算(示例代码未体现,可扩展)
四、算法执行过程演示
以4皇后问题为例,其搜索过程大致如下入所示,即不断试探,只要没有冲突就进入下一个状态,有冲突则回到上一个状态,知道找到一个解:
五、复杂度分析与优化方向
5.1 时间复杂度
- 最坏情况:O ( N ! ) O(N!)O(N!)
- 实际运行:通过剪枝大幅优化
5.2 空间复杂度
- O ( N ) O(N)O(N)(递归深度最多N层)
5.3 进阶优化思路
- 位运算优化:使用比特位表示状态
- 镜像剪枝:利用棋盘对称性减少计算量
- 并行计算:分治策略结合多线程
六、DFS的广泛应用场景
- 组合优化:全排列、子集生成
- 路径查找:迷宫求解、图连通性
- 游戏AI:围棋、象棋走法生成
- 依赖解析:软件包依赖管理
结语:算法之美的永恒追求
通过N皇后问题,我们不仅领略了DFS的精妙,更体会到算法设计中"暴力与优雅"的完美平衡。从19世纪的手工计算到现代计算机的毫秒级求解,算法的演进史正是人类智慧的见证。当您下次看到棋盘时,或许会会心一笑——这64个方格中,蕴藏着整个计算机科学的缩影。
思考题:如何修改算法使其可以统计解的个数而不记录具体位置?这会带来哪些性能提升?
希望这篇博客能帮助您在算法学习的道路上继续前行,下一站我们将探索广度优先搜索(BFS)的奇妙世界!
热门推荐
十六岁的人可以住酒店吗?失信被执行人又有哪些限制?
青春痘复发有哪些护理方法?
现代汉语语法基础知识讲义
如何购买股票?这些购买步骤有哪些实际应用?
基督山伯爵书中人物形象分析
如何了解各类基金的特点?不同类型的基金有哪些投资策略?
从类器官、细胞到真菌,生物计算技术多元"绽放"
如何根据工龄调整工资标准?
加湿器设计:从功能到美学的全方位考量
中国主要的水处理工艺是什么(国内污水厂现行四大主流处理方法)
科普 | 心梗发作那天我被诊断出重度焦虑症......
石膏拆除的最佳时间
2024云南经济这么干|玉溪:布局全产业链 助工业崛起
涉外律师需要掌握哪些法律知识?
手机显示HD的秘密大揭秘:高清视觉体验背后的技术与应用
南宁国际科技产业城项目落户青秀区,开启产城融合新篇章
提升员工满意度:薪酬福利策略的优化建议
揭秘艾滋病事前阻断:科学防线,守护健康未来
北京人民大会堂门票预约全攻略:时间、价格、入口及参观建议
《诛仙世界》《燕云十六声》年内铁上线?24年下半年MMO大作云集
新政频发,车路云一体化发展按下加速键
如何选择合适的证券公司进行投资?这些选择对投资结果有何影响?
上海交通大学先进电子材料与器件平台助推微纳加工领域攀高峰
假胯宽&大腿粗:幕后推手与逆袭攻略
三垣二十八宿的划分方法 地球的公转和自转
劳务派遣工的社保应该由谁缴纳
集成灶电路不通的故障排查与解决办法(炉火不能点燃)
明天起,请提前1小时吃早饭!
龙凤玉石的寓意:吉祥、尊贵与团圆
“氯吡格雷+奥美拉唑”,这个医嘱错在哪儿?