加拿大计算机竞赛CCC(Canada Computer Competition): 暑期训练营# 阶段1:递归与基本DFS(深度优先搜索)

🧭 阶段1:递归与基本DFS(深度优先搜索)


🎯 一、训练营目标

目标序号 目标内容
1 理解递归函数的定义、结构与执行机制(栈式调用过程)
2 掌握DFS(深度优先搜索)的实现方式,能够应用于图、网格搜索
3 掌握递归中的状态传递与返回路径,能解决多路径枚举类问题
4 学会设计递归出口与剪枝优化,避免爆栈和超时问题
5 熟悉基础递归/DFS题型在CCC J4/J5中出现的形式与变种

🧩 二、题型分类及典型代表

类别 题型描述 代表题目 涉及考点
数组/网格DFS 在二维网格中找路径/统计路径数量 ✅ CCC 2014 J4 - Party Invitation Grid 递归 + 网格移动 + 边界处理
树状递归结构 多分支递归结构体/枚举 ✅ 洛谷 P1217 [排列] ABC 字符串变换 多分支递归、字符处理
子集/组合枚举 枚举所有路径、排列、组合 ✅ 洛谷 P1036 [选数] 回溯、组合选择、剪枝
模拟DFS过程 根据规则模拟走法,判断是否能走通 ✅ 洛谷 P1596 [海底探险] DFS过程可视化、剪枝

📘 三、训练营详细内容

✅ 1. 递归基础语法

  • 函数调用自身(直接或间接)
  • 栈帧调用与返回值处理
  • 基础递归模型(如阶乘、斐波那契)
int factorial(int n) {
    if (n == 1) return 1; // 递归出口
    return n * factorial(n - 1); // 递归式
}

✅ 2. DFS结构与状态空间表示

  • 利用函数递归完成状态空间遍历
  • 用数组/矩阵表示搜索状态
  • 每次搜索尝试一个方向(图/网格)
void dfs(int x, int y) {
    if (x == endX && y == endY) {
        count++;
        return;
    }
    for (int d = 0; d < 4; ++d) {
        int nx = x + dx[d], ny = y + dy[d];
        if (合法(nx, ny)) {
            vis[nx][ny] = true;
            dfs(nx, ny);
            vis[nx][ny] = false; // 回溯
        }
    }
}

✅ 3. 剪枝与边界控制

  • 越界判断
  • 已访问判断(visited数组)
  • 不满足条件提前返回(剪枝)

✅ 4. 状态参数设计

  • 参数携带路径长度、值和等信息
  • 利用回溯撤回状态(如:组合选择)

✅ 5. 栈深分析与爆栈预防

  • 常规递归支持深度约 10^4 级
  • 若搜索状态数过大,建议使用非递归写法或限制搜索范围

🧪 四、典型训练题目推荐(附平台)

题目名称 类型 平台 说明
CCC 2014 J4 - Party Invitation Grid 网格DFS CEMC 从(0,0)走到(m,n),路径计数
洛谷 P1036 - 选数 组合递归 洛谷 选K个数使其和为质数
洛谷 P1596 - 海底探险 模拟DFS 洛谷 DFS走迷宫+剪枝
洛谷 P1217 - ABC字符串排列 枚举DFS 洛谷 多分支字符递归
洛谷 P1460 - 旅行家的预算 回溯路径枚举 洛谷 多路径决策

⏱️ 五、训练安排建议

任务编号 内容安排 建议目标
T1 ✅ 学习递归结构与基本递归函数实现
✅ 实现斐波那契数列、阶乘、幂运算等
理解递归机制,掌握调用栈工作原理
T2 ✅ 学习DFS搜索模板
✅ 尝试实现简单图/网格走法
掌握网格DFS模板,能进行路径枚举与计数
T3 ✅ 加入visited数组与边界控制
✅ 学习回溯与剪枝
学会写出合法搜索,掌握搜索空间控制与回退机制
T4 ✅ 综合练习题目
✅ 实战演练典型CCC真题
初步形成完整DFS解题能力,掌握路径搜索与优化技巧

🧠 六、总结归纳

知识点 说明 常见错误
递归出口 避免无限递归,保证存在停止条件 少写return或写错出口条件
DFS方向枚举 通常上下左右四个方向 方向数组写错,漏判断边界
visited数组 标记已走过路径,避免重复访问 忘记撤销,导致错误剪枝
剪枝优化 用于提升效率,过滤非法状态 剪枝条件过严漏解
回溯处理 恢复现场状态,确保其他分支正常进行 忘记回溯导致错误路径传播

🎁 附:通用DFS模板(C++)

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

int n, m;
bool vis[105][105];
char grid[105][105];

void dfs(int x, int y) {
    vis[x][y] = true;
    for (int d = 0; d < 4; d++) {
        int nx = x + dx[d];
        int ny = y + dy[d];
        if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny] && grid[nx][ny] != '#') {
            dfs(nx, ny);
        }
    }
}

posted @ 2025-06-17 12:25  kkman2000  阅读(27)  评论(0)    收藏  举报