文章目录

  • 1、DFS搜所有路径
  • 2、用栈记录和输出路径
  • 3、例题
    • 3.1 C++代码
    • 3.2 Python代码
  • 4、真题
    • 4.1 C++代码
    • 4.2 Python代码

  2022.12将出版蓝桥杯大赛用书《蓝桥杯大赛-程序设计竞赛专题挑战教程》,作者:蓝桥杯组委会、罗勇军。
  这本书解析了蓝桥杯大赛的常见考点,所有例题用C/C++、Python两种语言给出代码,适合C/C++组和Python组入门。
  本文的内容摘抄自这本书。

1、DFS搜所有路径

  DFS是一种暴力搜索,它能搜所有可能的情况。
  蓝桥杯大赛常常涉及到路径问题,需要用DFS寻找路径和输出路径,一般是输出一条符合要求的路径。
  DFS的特点是“一路到底”,遇到终点时,就得到了从起点到终点的一条路径。所以搜所有路径用DFS写代码最方便。下面看DFS如何找到所有的路径。
  图中,'@‘表示起点,’*‘表示终点,’.‘是可以走的点,’#'是墙壁不能走。

  图(1)是搜到的第一条路径。从起点(1, 1)出发,查询它的“左-上-右-下”哪个方向能走,发现“左-上”不能走,可以走“右”。第一步走到右边的(2,1)。然后从(2, 1)继续走,它可以向上走到(2, 0),但是后面就走不通了,退回来改走下面的(2, 2)。按这个方法,逐步深入走到终点,最后得到一条从起点(1, 1)到终点(0, 2)的路径“(1,1)->(2,1)->(2,2)->(1,2)->(0,2)”。后面C++代码中的a[nx][ny] = '#'的作用是“保存现场”。在这次DFS深入过程中,这条路径上曾经路过的点被“保存现场”,不允许再次经过。到达终点后,从终点退回,回溯寻找下一个路径。代码中的a[nx][ny] = '.'的作用是退回后“恢复现场”。
  图(2)是搜到的第二条路径。在图(1)搜到一条路径后,从终点(0, 2)退回到(1, 2),继续向下走到(1, 3)、(0, 3)、(0, 2)。
  图(3)是搜到的第三条路径。从终点(0, 2)一路退回到(2, 2)后,才找到新路径。在退回的过程中,原来被“保存现场的”(0, 3)、(1, 3)、(0, 2),重新被“恢复现场”,允许被经过。例如(1, 3),在第二条路径中曾用过,这次再搜新路径时,在第三条路径中重新经过了它。如果不“恢复现场”,这个点就不能在新路径中重新用了。
  总结“保存现场”和“恢复现场”的作用:
  (1)“保存现场”的作用,是禁止重复使用。当搜索一条从起点到终点的路径时,这条路径上经过的点,不能重复经过,否则就兜圈子了,所以路径上的点需要“保存现场”,禁止再经过它。没有经过的点,或者碰壁后退回的点,都不能“保存现场”,这些点可能后面会进入这条路径。
  (2)“恢复现场”的作用。当重新搜新的路径时,方法是从终点(或碰壁的点)沿着旧路径逐步退回,每退回一个点,就对这个点“恢复现场”,允许新路径重新经过这个点。例如图(2)和图(3)的点(1, 3)。

2、用栈记录和输出路径

  在DFS中,用栈来跟踪DFS的过程,记录走过的路径,是最方便的。DFS到某个格子时,把这个格子放到栈里,表示路径增加了这个格子。DFS回溯的时候,退出了这个格子,表示路径上不再包括这个格子,需要从栈中弹走这个格子。

3、例题

  下面是本文自创的例题,演示上述的两个功能:
  (1)用DFS搜索从起点到终点的所有路径;
  (2)用栈记录路径。


例题:输出所有路径
题目描述】给出一张格子图,输出从起点到终点的所有路径。
输入描述】第一行是整数n,m,分别是行数和列数。后面n行,每行m个符号。只有两种符号:’•’能走,’#’是墙壁不能走。在每一步,都按左-上-右-下的顺序搜索。左上角是起点,坐标(0, 0),右下角是终点,坐标(n-1, m-1)。
输出描述】输出所有的路径。为了方便表示,约定每个小格子用一个数字代表,从西北角(左上角)开始编号: 0, 1, 2, 3…
样例输入1

3 2
..
..
..

样例输出1

0 2 4 5
0 2 3 5
0 1 3 2 4 5
0 1 3 5

样例输入2

3 4
....
..#.
....

样例输出2

0 4 8 9 5 1 2 3 7 11
0 4 8 9 10 11
0 4 5 1 2 3 7 11
0 4 5 9 10 11
0 1 5 4 8 9 10 11
0 1 5 9 10 11
0 1 2 3 7 11

3.1 C++代码

  下面代码中的函数dfs()搜索出所有代码,并打印出来。
  vector<int>path是一个栈,用于记录路径。在dfs()函数的开始,到达出口时,就根据path打印出路径。

#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[25][25];   //存储格子图
vector<int> path;                    //path是一个栈,记录路径
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};   //4个方向:左、上、右、下void dfs(int x,int y){if(x==n-1 && y==m-1){          //终止条件:到达出口for(int i = 0;i < path.size();i++)cout << path[i] <<" ";cout<<endl;return;}for(int i = 0;i < 4;i++){int nx = x + dir[i][0],ny = y + dir[i][1];if(nx>=0 && nx<n && ny>=0 && ny<m && a[nx][ny]=='.'){a[nx][ny]='#';path.push_back(nx*m + ny); //进栈,记录路径dfs(nx,ny);path.pop_back();           //出栈,DFS回溯a[nx][ny]='.';}}
}
int main(){cin >> n>>m;for(int i=0;i<n;i++)for(int j=0;j<m;j++)cin>>a[i][j];path.push_back(0);a[0][0]='#';dfs(0,0);return 0;
}

3.2 Python代码

  下面的Python代码和上面的C++代码逻辑一样。注意它使用栈的方法,用一个list数组 path=[]模拟栈。

def dfs(x,y):    if x==n-1 and y==m-1:    #到达终点for i in range(len(path)): print(path[i],end=' ')print()  #换行returndir = ((-1, 0), (0, -1),(1, 0),  (0, 1)) #4个方向:左、上、右、下for u,v in dir:  #遍历4个方向的邻居nx = x+u; ny = y+v    #邻居的坐标if 0<=nx<n and 0<=ny<m and a[nx][ny]=='.':    a[nx][ny]='#'          #保存现场:这个点在这次更深的dfs中不能再用path.append(nx*m + ny) #进栈,把这个点记录到路径里dfs(nx, ny)path.pop();            #出栈,释放这个点a[nx][ny]='.'          #恢复现场:回溯后这个点可以再次用n,m = map(int, input().split())    #n行、m列
a=[]
for i in range(n):                 #读图,存到二维矩阵a[n][m],n行m列a.append(list(input()))
path = []                          #用栈记录路径
path.append(0)
a[0][0]='#'
dfs(0,0)

4、真题

  下面的真题,是上面讲解的知识点的直接应用。


路径之谜 2016年第七届决赛,lanqiaoOJ第89题 https://www.lanqiao.cn/problems/89/learning/
题目描述】小明冒充X星球的骑士,进入了一个奇怪的城堡。城堡里边什么都没有,只有方形石头铺成的地面。假设城堡地面是n×n个方格。按习俗,骑士要从西北角走到东南角。可以横向或纵向移动,但不能斜着走,也不能跳跃。每走到一个新方格,就要向正北方和正西方各射一箭。(城堡的西墙和北墙内各有n个靶子)同一个方格只允许经过一次。但不必走完所有的方格。如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)
输入格式】第一行一个整数N(0<N<20),表示地面有N×N个方格;第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东);第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)。
输出格式】一行若干个整数,表示骑士路径。为了方便表示,我们约定每个小格子用一个数字代表,从西北角(左上角)开始编号: 0, 1, 2, 3…


  又是一道格子搜索题,这种题在蓝桥杯大赛中很常见。
  题目要求输出一条路径,用DFS是很合适的,DFS搜索过程中,自然生成一条路径。
  每走到一个格子,对应的靶子上箭多一支,靶子上的箭等于给定的数字后,就不用再DFS下去了。这是一个简单的剪枝。
  注意DFS时记录路径的技巧。根据题目的要求,用栈来跟踪DFS的过程,记录DFS走过的路径,是最方便的。DFS到某个格子时,把这个格子放到栈里,表示路径增加了这个格子。DFS回溯的时候,退出了这个格子,表示路径上不再包括这个格子,需要从栈中弹走这个格子。

4.1 C++代码

#include<bits/stdc++.h>
using namespace std;
int n;
int a[25],b[25],vis[25][25];
vector<int> path;                  //记录路径
int d[4][2]={1,0,-1,0,0,1,0,-1};   //上下左右
void dfs(int x,int y){if(a[x]<0 || b[y]<0) return;   //剪枝if(x==n-1 && y==n-1){          //走到出口int ok=1;for(int i = 0;i < n;i++)if(a[i]!=0 || b[i]!=0){ ok=0; break;}if(ok)for(int i = 0;i < path.size();i++)   cout << path[i] <<" ";}for(int i = 0;i < 4;i++){int tx = x + d[i][0],ty = y + d[i][1];if(vis[tx][ty]==0 && tx>=0 && tx<n && ty>=0 && ty<n){vis[tx][ty]=1;path.push_back(tx*n + ty); //进栈,记录路径a[tx]--;    b[ty]--;dfs(tx,ty);path.pop_back();           //出栈,DFS回溯a[tx]++;    b[ty]++;vis[tx][ty]=0;}}
}
int main(){cin >> n;for(int i=0;i<n;i++) cin >> b[i];  //北面靶子for(int i=0;i<n;i++) cin >> a[i];  //西面靶子path.push_back(0);vis[0][0]=1;a[0]--;  b[0]--;dfs(0,0);return 0;
}

4.2 Python代码

def dfs(x,y):if a[x]<0 or b[y]<0: returnif x==n-1 and y==n-1:ok=1for i in range(n):if a[i]!=0 or b[i]!=0: ok=0; breakif ok==1:for i in range(len(path)): print(path[i],end=' ')for d in [(1,0),(-1,0),(0,1),(0,-1)]:tx = x+d[0]; ty = y+d[1]if 0 <= tx < n and 0 <= ty < n and vis[tx][ty] == 0:vis[tx][ty] = 1path.append(tx*n + ty)      #进栈,记录路径a[tx] -= 1; b[ty] -= 1dfs(tx, ty)path.pop();                 #出栈,DFS回溯a[tx] += 1;  b[ty] += 1vis[tx][ty] = 0n = int(input())
vis = [[0]*n for i in range(n)]
path = []               #用栈记录路径
path.append(0)
b = list(map(int,input().split()))
a = list(map(int,input().split()))
vis[0][0]=1
a[0] -= 1;  b[0] -= 1
dfs(0,0)

DFS搜索和输出所有路径相关推荐

  1. 【CCCC】L3-014 周游世界 (30分),,DFS搜索最短路,路径打印

    problem L3-014 周游世界 (30分) 周游世界是件浪漫事,但规划旅行路线就不一定了-- 全世界有成千上万条航线.铁路线.大巴线,令人眼花缭乱.所以旅行社会选择部分运输公司组成联盟,每家公 ...

  2. 【CCCC】L3-025 那就别担心了 (30分),dfs搜索起点到终点的路径条数。

    problem L3-025 那就别担心了 (30分) 下图转自"英式没品笑话百科"的新浪微博 -- 所以无论有没有遇到难题,其实都不用担心. ziqia.jpg 博主将这种逻辑推 ...

  3. nyist 27 水池数目(dfs搜索)

     水池数目 时间限制: 3000 ms  |  内存限制: 65535 KB 难度: 4 描述 南阳理工学院校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图 ...

  4. bfs dfs 搜索入门模板题

    bfs & dfs 题目链接:https://vjudge.net/contest/404511 1.最短路(bfs) (1)一维最短路 D - Catch That Cow 题目大意: 在一 ...

  5. 4013基于深度优先搜索的两顶点路径存在与否的判断

    描述 设计一个算法,试基于深度优先搜索判断以邻接表方式存储的有向图中是否存在由顶点vi 输入 多组数据,每组m+3数据行.第一行有两个数字n和m,代表有n个顶点和m条边.第二行有n个字符,代表n个顶点 ...

  6. hexo 搜索_Hexo--本地搜索localsearch之url路径问题

    Hexo localsearch 本地搜索 路径问题 / 什么是本地搜索 针对本地存储文件内容进行搜索,也就是我们搜索的内容都在本地 Hexo 本地搜索 localsearch 我们用的本地搜素插件是 ...

  7. sdut 2152:Balloons(第一届山东省省赛原题,DFS搜索)

    Balloons Time Limit: 1000MS Memory limit: 65536K 题目描述 Both Saya and Kudo like balloons. One day, the ...

  8. nyist oj 19 擅长排列的小明(dfs搜索+STL)

    擅长排列的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描写叙述 小明十分聪明.并且十分擅长排列计算.比方给小明一个数字5,他能立马给出1-5按字典序的全排列,假设你想 ...

  9. SRPG游戏开发(二十七)第七章 寻路与地图对象 - 五 搜索移动范围与路径(Search Move Range and Path)

    返回总目录 第七章 寻路与地图对象(Pathfinding and Map Object) 这一章主要进行寻路与地图对象的部分工作. 文章目录 第七章 寻路与地图对象(Pathfinding and ...

最新文章

  1. NA-NP-IE系列实验36:扩展ACL
  2. cmd做个定时弹窗_揭秘200元山寨苹果耳机!一颗耳边的“定时炸弹”...
  3. ansys scade suite 2020中文版
  4. 权重对生成对抗网络GAN性能的影响
  5. 【技术综述】深度学习中的数据增强(下)
  6. mysql构建数据立方体_OLAP数据建模工具Workbench的初步使用(数据立方体的建立)
  7. 我通过了 Google 技术面试,所以你也能行!
  8. SOLR对多个(关联)表创建索引
  9. c 语言程序设计基础题答案,C语言程序设计基础教程_习题答案
  10. JMeter-接口测试
  11. iOS开发1小时快速入门
  12. C语言(动态开辟二维数组 指针数组、数组指针、一维数组模拟开辟)
  13. 如何查看linux是grub还lilo,linux中LILO及GRUB配置实例
  14. Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流)
  15. 数学常用符号、表达式的英文读法小结
  16. 跨境电商独立站转化率提升神器-SaleSmartly
  17. 物联网与AI芯片密不可分 企业加速跑马圈地
  18. Polar SC的C++实现
  19. CDH大数据平台 ERROR Heartbeating to 192.168.0.200:7182 failed
  20. 国务院办公厅关于2013年部分节假日安排的通知(转载)

热门文章

  1. 京东实习笔试——站队
  2. 这几款app疫情期间活跃度为何如此高?方法太可了吧
  3. 2020IT从业者如何找到高薪工作
  4. 判断图有无环_数读湾区经济潜能:基于大数据分析的环杭州湾大湾区“一体化”发展潜能!...
  5. 亿万第一至二季/全集Billions迅雷下载
  6. java符号三角形问题_实验四 回溯算法和分支限界法 符号三角形问题
  7. python123 第四次作业答案_Python第四次作业——黄亦杨
  8. sdk manager extra下没有Google play billing
  9. 汽车高级驾驶辅助系统ADAS功能盘点
  10. 一篇关于大黄蜂的鸡汤文的杂想