跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

蓝桥杯算法实战指南:递推、递归、BFS 与 DFS 详解

本指南涵盖蓝桥杯竞赛中的核心算法实战,包括递推、递归、BFS 广度优先搜索及 DFS 深度优先搜索。文章通过具体例题解析递推的状态转移与边界处理,强调递归终止条件的重要性。针对图论问题,详细对比了邻接矩阵与邻接表在 BFS/DFS 中的应用场景,并提供了 C++ 标准库实现的完整代码模板。迷宫问题部分展示了如何利用 DFS 判断连通性以及利用 BFS 求解最短路,重点分析了不同算法的时间复杂度差异及实际编码中的注意事项,如数据溢出处理和数组初始化。

BackendPro发布于 2026/3/26更新于 2026/10/2593 浏览
蓝桥杯算法实战指南:递推、递归、BFS 与 DFS 详解

递推和递归

递推

递推算法的核心在于自底向上,由已知条件推导出结果。关键在于确定状态转移方程、边界条件和关系式。

直接通过题目来理解递推思想。以棋盘路径问题为例:从 A 点到 B 点的路径数,且经过马能到达的点都无效。

首先定义移动方向和标记数组。

// 马走日,移动的位置(马能到达的点)
int mx[] = {-1,-1,-2,-2,1,1,2,2}; 
int my[] = {-2,2,-1,1,-2,2,-1,1}; 
int vis[110][110]={0};// 标记数组 
int rd[110][110]={0};// 记录每个点的路径数 

将马能到达的位置全标记成 1,包括初始位置。

for(int i=0;i<=7;i++){
    int nx=cx+mx[i]; 
    int ny=cy+my[i]; 
    if(nx<0 || ny<0 || nx>n || ny>m)continue; 
    vis[nx][ny]=1; 
}
vis[cx][cy]=1;

初始化边界,起点置为一。注意左边界和上边界的处理,如果该点被马标记则路径数为 0。

rd[0][0]=1; 
for(int i=1;i<=n;i++){
    rd[i][0]=rd[i-1][0]; 
    if(vis[i][0]==1)rd[i][0]=0; 
}
for(int i=1;i<=m;i++){
    rd[0][i]=rd[0][i-1]; 
    if(vis[0][i]==1)rd[0][i]=0; 
}

卒只能向下或向右移动,因此到达点 (i, j) 的路径数等于上方点与左方点路径数之和。 关系式:rd[i][j] = rd[i-1][j] + rd[i][j-1]

for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        if(vis[i][j]==1)continue; 
        rd[i][j]=rd[i-1][j]+rd[i][j-1]; 
    } 
}

完整代码如下。注意数据范围可能溢出,需使用 long long。

#include<bits/stdc++.h> 
using namespace std; 
#define int long long 
int mx[] = {-1,-1,-2,-2,1,1,2,2}; 
int my[] = {-2,2,-1,1,-2,2,-1,1}; 
int vis[110][110]={0}; 
int rd[110][110]={0}; 
signed main(){ 
    int n,m,cx,cy; 
    cin>>n>>m>>cx>>cy; 
    vis[cx][cy]=1; 
    for(int i=0;i<=7;i++){
        int nx=cx+mx[i]; 
        int ny=cy+my[i]; 
        if(nx<0 || ny<0 || nx>n || ny>m)continue; 
        vis[nx][ny]=1; 
    } 
    rd[0][0]=1; 
    for(int i=1;i<=n;i++){
        rd[i][0]=rd[i-1][0]; 
        if(vis[i][0]==1)rd[i][0]=0; 
    } 
    for(int i=1;i<=m;i++){
        rd[0][i]=rd[0][i-1]; 
        if(vis[0][i]==1)rd[0][i]=0; 
    } 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(vis[i][j]==1)continue; 
            rd[i][j]=rd[i-1][j]+rd[i][j-1]; 
        } 
    } 
    cout<<rd[n][m]<<endl; 
    return 0; 
}

核心要点: 递推有两要素:边界条件和关系式。只要正确推出这两个要素,再从已知推未知,就可以轻松解决递推问题。

递归

经典引入

递归算法是直接或间接调用自身函数,通过循环回溯解决小问题,最后得出大问题的答案。核心是找到终止条件,否则会导致无限循环。

以斐波那契数列为例,公式为 f(n) = f(n-1)+f(n-2)。在函数中,当前第 n 位函数调用前两位,直到最底层返回结果。

int fb(int x){ 
    if(x==1 || x==2)return 1; 
    return fb(x-1)+fb(x-2); 
}

完整代码示例:

#include<bits/stdc++.h> 
using namespace std; 
int fb(int x){ 
    if(x==1 || x==2)return 1; 
    return fb(x-1)+fb(x-2); 
} 
int main(){ 
    int n; 
    cin>>n; 
    while(n--){ 
        int num; 
        cin>>num; 
        cout<<fb(num)<<endl; 
    } 
}
深入理解

结合正则表达式最长字符串匹配问题。规则如下:

  • ( ) 及内容视为一组。
  • | 为分界线,两边长度互不干扰,取最大值。
  • x 为普通字符。

例如 ((xx|xxx)x|(x|xx))xx,先拆分组,计算每组最大长度,再累加普通字符。

核心逻辑是不断找组,根据符号判断。由于代码较完整,直接展示带注释的解法。

#include<bits/stdc++.h> 
using namespace std; 
int i=0; 
string s; 
int Longest(){ 
    int m_cnt=0; 
    int cnt=0; 
    while(i < s.size()){
        if(s[i] == '('){ 
            i++; 
            int n = Longest(); 
            cnt += n; 
        } else if(s[i] == 'x'){ 
            cnt++; 
            i++; 
        } else if(s[i] == '|'){ 
            m_cnt = max(m_cnt,cnt); 
            cnt=0; 
            i++; 
        } else { 
            i++; 
            break; 
        } 
    } 
    return max(cnt,m_cnt);
} 
int main(){ 
    cin>>s; 
    cout<<Longest(); 
}

核心要点: 递归最重要的一步是找到终止条件。找到式子间的关系,再循环调用即可解决问题。

BFS 广度优先搜索

基础模板

BFS 是一种图的遍历算法,从浅到深,宽度遍历。从一个节点开始,找它的邻居,再找邻居的邻居。

实现方式主要有两种:邻接矩阵和邻接表。邻接矩阵结构简单但空间复杂度高;邻接表适合数据量大的情况。

邻接矩阵实现

适用于无向图,n 个点,m 条边。

#include<bits/stdc++.h> 
using namespace std; 
int g[105][105]; 
int vis[105]; 
int n,m; 
void bfs(int start){ 
    queue<int> q; 
    q.push(start); 
    vis[start] = 1; 
    while(!q.empty()){ 
        int cur = q.front(); 
        q.pop(); 
        for(int i=1;i<=n;i++){ 
            if(g[cur][i] == 1 && vis[i] == 0){ 
                vis[i] = 1; 
                q.push(i); 
            } 
        } 
    } 
}
int main(){ 
    cin >> n >> m; 
    for(int i=1;i<=m;i++){ 
        int u,v; 
        cin >> u >> v; 
        g[u][v] = 1; 
        g[v][u] = 1; 
    } 
    bfs(1); 
    return 0; 
}
邻接表实现
#include<bits/stdc++.h> 
using namespace std; 
vector<int> adj[105]; 
int vis[105]; 
int n,m; 
void bfs(int start){ 
    queue<int> q; 
    q.push(start); 
    vis[start] = 1; 
    while(!q.empty()){ 
        int cur = q.front(); 
        q.pop(); 
        for(int i=0;i<adj[cur].size();i++){ 
            int nxt = adj[cur][i]; 
            if(vis[nxt] == 0){ 
                vis[nxt] = 1; 
                q.push(nxt); 
            } 
        } 
    } 
}
int main(){ 
    cin >> n >> m; 
    for(int i=1;i<=m;i++){ 
        int u,v; 
        cin >> u >> v; 
        adj[u].push_back(v); 
        adj[v].push_back(u); 
    } 
    bfs(1); 
    return 0; 
}

BFS 最短路问题

在无向图中求两点间最短路径。BFS 第一次走到某个点时,即为最短路径。

需要记录步数,结构体存储节点 ID 和步数。

#include<bits/stdc++.h> 
using namespace std; 
vector<int> adj[105]; 
int vis[105]; 
int n,m; 
int a,b; 
struct node{ 
    int id; 
    int step; 
}; 
void bfs(int start){ 
    queue<node> q; 
    node tmp; 
    tmp.id = start; 
    tmp.step = 0; 
    q.push(tmp); 
    vis[start] = 1; 
    while(!q.empty()){ 
        int curId = q.front().id; 
        int curStep = q.front().step; 
        q.pop(); 
        for(int i=0;i<adj[curId].size();i++){ 
            node nxt; 
            nxt.id = adj[curId][i]; 
            nxt.step = curStep + 1; 
            if(nxt.id == b){ 
                cout << nxt.step << endl; 
                return; 
            } 
            if(vis[nxt.id] == 0){ 
                vis[nxt.id] = 1; 
                q.push(nxt); 
            } 
        } 
    } 
}
int main(){ 
    cin >> n >> m; 
    for(int i=1;i<=m;i++){ 
        int u,v; 
        cin >> u >> v; 
        adj[u].push_back(v); 
        adj[v].push_back(u); 
    } 
    cin >> a >> b; 
    bfs(a); 
    return 0; 
}

DFS 深度优先搜索

基础模板

DFS 算法纵向搜索,尽可能深地探入,直到无法搜索,然后回溯。核心思想是递归调用。

同样提供邻接矩阵和邻接表两种实现。

邻接矩阵实现
#include<bits/stdc++.h> 
using namespace std; 
const int N=1000; 
int a[N][N]; 
int vis[N]; 
void dfs(int cur){ 
    vis[cur]=1; 
    for(int i=1;i<=n;i++){ 
        if(a[cur][i]==1 && vis[i]==0){ 
            dfs(i); 
        } 
    } 
}
int main(){ 
    cin >> n >> m; 
    for(int i=1;i<=m;i++){ 
        int u,v; 
        cin >> u >> v; 
        a[u][v]=1; 
        a[v][u]=1; 
    } 
    dfs(1); 
    return 0; 
}
邻接表实现
#include<bits/stdc++.h> 
using namespace std; 
const int N=1000; 
vector<int>a[N]; 
int vis[N]; 
void dfs(int cur){ 
    vis[cur]=1; 
    for(int i=1<a[cur].size();i++){ 
        int nxt=a[cur][i]; 
        if(vis[nxt]==0){ 
            dfs(i); 
        } 
    } 
}
int main(){ 
    cin >> n >> m; 
    for(int i=1;i<=m;i++){ 
        int u,v; 
        cin >> u >> v; 
        a[u].push_back(v); 
        a[v].push_back(u); 
    } 
    dfs(1); 
    return 0; 
}

迷宫问题

DFS 版

迷宫问题通常要求判断能否从起点走到终点。支持上下左右移动,不能穿墙。

多组测试数据时,建议使用邻接矩阵而非邻接表,因为输入新数据时旧数据会被清空,避免清理动态数组的麻烦。

需要方向数组控制移动:nx[]={-1,0,0,1}, ny[]={0,-1,1,0}。

#include<bits/stdc++.h> 
using namespace std; 
int n; 
char maze[110][110]; 
int vis[110][110]; 
int xA,yA,xB,yB; 
int nx[]={-1,0,0,1}; 
int ny[]={0,-1,1,0}; 
bool judge(int x,int y){ 
    if(x<0 || y<0 || x>=n || y>=n)return false; 
    if(maze[x][y]=='.')return true; 
    else return false; 
} 
bool dfs(int sx,int sy){ 
    int cur_x=sx; 
    int cur_y=sy; 
    vis[cur_x][cur_y]=1; 
    if(cur_x == xB && cur_y == yB)return true; 
    for(int i=0;i<4;i++){ 
        int nxt_x=cur_x+nx[i]; 
        int nxt_y=cur_y+ny[i]; 
        if(judge(nxt_x,nxt_y) && vis[nxt_x][nxt_y]==0){ 
            if(dfs(nxt_x,nxt_y))return true; 
        } 
    } 
    return false; 
}
int main(){ 
    int k; 
    cin>>k; 
    while(k--){ 
        cin>>n; 
        for(int i=0;i<n;i++){ 
            for(int j=0;j<n;j++){ 
                char c; 
                cin>>c; 
                maze[i][j]=c; 
                vis[i][j]=0; 
            } 
        } 
        cin>>xA>>yA>>xB>>yB; 
        bool ans=dfs(xA,yA); 
        if(ans)cout<<"YES"<<endl; 
        else cout<<"NO"<<endl; 
    } 
    return 0; 
}

BFS 版

BFS 版本用于求解迷宫最短路。DFS 需要罗列所有路径,复杂度指数级;BFS 第一次走到终点即为最短路,复杂度 O(n)。

基本思路相同,主要区别在于使用队列存储状态。

#include<iostream> 
#include<queue> 
using namespace std; 
int n; 
char maze[110][110]; 
int vis[110][110]; 
int xA, yA, xB, yB; 
int nx[] = {-1, 0, 0, 1}; 
int ny[] = {0, -1, 1, 0}; 
bool judge(int x, int y) { 
    if (x < 0 || y < 0 || x >= n || y >= n) return false; 
    if (maze[x][y] == '.') return true; 
    else return false; 
} 
void bfs(int sx, int sy) { 
    queue<pair<int, int>> q; 
    q.push({sx, sy}); 
    vis[sx][sy] = 1; 
    while (!q.empty()) { 
        int cur_x = q.front().first; 
        int cur_y = q.front().second; 
        q.pop(); 
        if (cur_x == xB && cur_y == yB) { 
            return; 
        } 
        for (int i = 0; i < 4; i++) { 
            int nxt_x = cur_x + nx[i]; 
            int nxt_y = cur_y + ny[i]; 
            if (judge(nxt_x, nxt_y) && vis[nxt_x][nxt_y] == 0) { 
                q.push({nxt_x, nxt_y}); 
                vis[nxt_x][nxt_y] = 1; 
            } 
        } 
    } 
}
int main() { 
    int k; 
    cin >> k; 
    while (k--) { 
        cin >> n; 
        for (int i = 0; i < n; i++) { 
            for (int j = 0; j < n; j++) { 
                char c; 
                cin >> c; 
                maze[i][j] = c; 
                vis[i][j] = 0; 
            } 
        } 
        cin >> xA >> yA >> xB >> yB; 
        bfs(xA, yA); 
        if (vis[xB][yB]) cout << "YES" << endl; 
        else cout << "NO" << endl; 
    } 
    return 0; 
}

以上就是迷宫问题的基本思路和解法,希望带给大家一点启发。

目录

  1. 递推和递归
  2. 递推
  3. 递归
  4. 经典引入
  5. 深入理解
  6. BFS 广度优先搜索
  7. 基础模板
  8. 邻接矩阵实现
  9. 邻接表实现
  10. BFS 最短路问题
  11. DFS 深度优先搜索
  12. 基础模板
  13. 邻接矩阵实现
  14. 邻接表实现
  15. 迷宫问题
  16. DFS 版
  17. BFS 版

更多推荐文章

查看全部
  • 使用 Mac Mini 部署 OpenClaw 打造金融 AI 分析助手
  • Adobe Illustrator 2025 安装步骤与使用技巧指南
  • B 站:从二次元社区到 AI 创新孵化器的转变
  • Python 列表转 Excel 实战:一维、二维与字典格式
  • HTML 网页结构搭建:从语义化标签到整站规划
  • .NET 集成 GoView 低代码可视化大屏实战详解
  • Spring AI 重塑 Java 生态 AI 开发实践
  • 二分答案专题实战:木材加工与砍树问题详解
  • 绿联 NAS 配置 WebDAV 公网访问及 RaiDrive 挂载实战
  • 通达信主力建仓指标源码
  • Flutter Web 开发:解决跨域(CORS)问题的方法
  • 图论算法总结:单源最短路(Dijkstra 与 SPFA)
  • Dify 本地 Docker 部署教程
  • Vitis 实战:从零将 AI 模型部署到 FPGA
  • C++ 实现 LRU Cache 缓存淘汰算法
  • 渗透测试实战:SRC 漏洞挖掘与提交流程指南
  • 自然语言处理在客户服务领域的应用与实战
  • OpenClaw 自动化与定时任务实战指南
  • Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测
  • 使用 Python 和 Itchat 实现微信定时消息与自动回复

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online