1. 深度优先搜索(DFS)算法基础解析
深度优先搜索(Depth-First Search)是算法竞赛中最基础的搜索策略之一,也是递归思想的经典应用。它的核心运作机制可以用"不撞南墙不回头"来形容——算法会沿着当前路径一直深入探索,直到无法继续前进时才回溯到上一个分叉点。
1.1 DFS的核心特性
DFS之所以成为算法竞赛的必备技能,主要基于以下几个关键特性:
-
递归实现天然契合:DFS的"深入探索-回溯"机制与函数调用栈的特性完美匹配。每次递归调用相当于向更深层次探索,函数返回则对应回溯过程。
-
空间复杂度优势:相比广度优先搜索(BFS),DFS通常只需要存储当前路径上的节点。对于深度为d的搜索树,空间复杂度仅为O(d),而BFS需要O(b^d)(b为分支因子)。
-
全遍历保证:在树或图结构中,DFS能够系统地探索所有可能的路径,确保不遗漏任何解空间。
实际编程竞赛中,DFS常用于解决组合问题(如子集生成)、排列问题(如全排列)、路径搜索(如迷宫求解)等场景。它的变体包括记忆化搜索、迭代加深搜索等高级技巧。
1.2 典型问题解决框架
一个标准的DFS实现通常包含以下要素:
cpp复制void dfs(当前状态) {
if (到达终止条件) {
处理结果;
return;
}
for (所有可能的扩展方式) {
if (满足约束条件) {
做出选择;
dfs(新状态);
撤销选择; // 回溯关键步骤
}
}
}
这个模板中,回溯步骤是最容易被初学者忽略的关键。它确保了状态空间的正确遍历,就像探索迷宫时需要在岔路口做标记一样重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 选数问题:组合与素数判断
2.1 问题建模与分析
选数问题要求从n个整数中选取k个,使其和为素数。这是一个典型的组合问题,解空间规模为C(n,k)。使用DFS的优势在于可以系统性地枚举所有可能的组合。
关键设计决策:
- 状态表示:使用位置指针pos避免重复组合(如[1,2]和[2,1]被视为相同)
- 剪枝策略:当已选数cnt达到k时立即返回,避免无效搜索
- 素数判断优化:使用平方根作为遍历上限(i <= sqrt(num))
2.2 代码实现详解
cpp复制#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
vector<int> nums; // 存储输入数字
int n, k; // 总数和需要选择的数
int current_sum = 0; // 当前选数总和
int selected = 0; // 已选数量
int result = 0; // 符合条件的结果数
bool is_prime(int num) {
if (num <= 1) return false;
if (num <= 3) return true; // 2和3是素数
if (num%2 == 0 || num%3 == 0) return false;
// 检查6k±1形式的因数
for(int i = 5; i*i <= num; i += 6) {
if (num%i == 0 || num%(i+2) == 0)
return false;
}
return true;
}
void dfs(int pos) {
if (selected == k) {
if (is_prime(current_sum))
result++;
return;
}
// 从pos开始避免重复组合
for (int i = pos; i < n; i++) {
current_sum += nums[i];
selected++;
dfs(i + 1); // 关键:下一位置从i+1开始
sele
