跳到主要内容
蓝桥杯算法实战指南:递推、递归、BFS 与 DFS 详解 | 极客日志
C++ 算法
蓝桥杯算法实战指南:递推、递归、BFS 与 DFS 详解 本指南涵盖蓝桥杯竞赛中的核心算法实战,包括递推、递归、BFS 广度优先搜索及 DFS 深度优先搜索。文章通过具体例题解析递推的状态转移与边界处理,强调递归终止条件的重要性。针对图论问题,详细对比了邻接矩阵与邻接表在 BFS/DFS 中的应用场景,并提供了 C++ 标准库实现的完整代码模板。迷宫问题部分展示了如何利用 DFS 判断连通性以及利用 BFS 求解最短路,重点分析了不同算法的时间复杂度差异及实际编码中的注意事项,如数据溢出处理和数组初始化。
BackendPro 发布于 2026/3/26 0 浏览递推和递归
递推
递推算法的核心在于自底向上,由已知条件推导出结果。关键在于确定状态转移方程、边界条件和关系式。
直接通过题目来理解递推思想。以棋盘路径问题为例:从 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][ ]=rd[i ][ ];
(vis[i][ ]== )rd[i][ ]= ;
}
( i= ;i<=m;i++){
rd[ ][i]=rd[ ][i ];
(vis[ ][i]== )rd[ ][i]= ;
}
0
-1
0
if
0
1
0
0
for
int
1
0
0
-1
if
0
1
0
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 是一种图的遍历算法,从浅到深,宽度遍历。从一个节点开始,找它的邻居,再找邻居的邻居。
实现方式主要有两种:邻接矩阵和邻接表。邻接矩阵结构简单但空间复杂度高;邻接表适合数据量大的情况。
邻接矩阵实现 #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 第一次走到某个点时,即为最短路径。
#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 ;
}
以上就是迷宫问题的基本思路和解法,希望带给大家一点启发。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,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
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online