当前位置:   article > 正文

深度优先搜索算法(DFS)_深度优先搜索之孙悟空救唐僧

深度优先搜索之孙悟空救唐僧

过程:

对每一个可能的分支路径深入到不能再深入为止。而且每个节点只能访问一次

【第一题:孙悟空找师傅】

问题描述:

西游路上咱们的唐长老又一次被妖怪抓走了。已知妖怪洞穴是一个N*N 的正方形,其中有一些假山堵路。
输入:第一行是一个正整数N(2<N<10),后面包含N*N行由0,1,2组成的矩阵,其中0表示可以走,1表示假山,2表示师傅的位置。
输出:如果悟空和八戒可以救出师傅就输出YES,否则就输出NO。
样例输入1:

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

样例输出1:
 

YES

样例输入 2:

  1. 3
  2. 0 0 0
  3. 0 1 1
  4. 0 1 2

样例输入2:

NO

运用递归的思想,在二维的数组里面遍历上下左右四个方向

代码实现:

  1. #include<iostream>
  2. using namespace std;
  3. int dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};//控制搜索方向
  4. //确保四个方向能够搜到
  5. int G[105][105],vis[105][105]; //G存储地图,
  6. //vis标记是否搜索过
  7. int n;//n为地图的长和宽
  8. bool f=false;//标记是否能够找到师傅
  9. void dfs(int x,int y){//如果找到师傅则结束
  10. if(G[x][y]==2){
  11. cout<<x<<" "<<y<<endl;
  12. f=true;
  13. return;
  14. }
  15. //开始搜索
  16. for(int i=0;i<4;i++){ //四个方向
  17. int xx=x+dx[i];
  18. int yy=y+dy[i];
  19. if(xx>=0&&xx<n&&yy>=0&&yy<n&&G[xx][yy]!=1&&vis[xx][yy]==0){
  20. vis[xx][yy]=1;//标记xx yy位置已经搜索过了
  21. dfs(xx,yy);//从xx yy位置开始搜索
  22. vis[xx][yy]=0;//回溯
  23. }
  24. }
  25. }
  26. int main(){
  27. cin>>n;
  28. for(int i=0;i<n;i++){
  29. for(int j=0;j<n;j++){
  30. cin>>G[i][j];
  31. }
  32. }
  33. if(G[0][0]==1){
  34. cout<<"NO"<<endl;
  35. return 0;
  36. }
  37. else if(G[0][0]==2){
  38. cout<<"YES"<<endl;
  39. return 0;
  40. }
  41. else{
  42. vis[0][0]=1;//标记0 0 位置搜索过了
  43. dfs(0,0);
  44. if(f){
  45. cout<<"YES"<<endl;
  46. }
  47. else{
  48. cout<<"NO"<<endl;
  49. }
  50. }
  51. return 0;
  52. }

【第二题:传送门】

问题描述:

观音有一件法宝,叫做传送门,我们可以通过这件法宝从妖怪洞穴出去了,观音把这件法宝放在了一个妖怪洞穴,我们只要找到那个洞穴就可以出去了。观音已经把放法宝洞穴的坐标告诉我们了,我们需要编程确定一下是否能到达那个洞穴就行了。

输入:第一行包含一个正整数N(1<n<30)表示迷宫的长和宽,下面N行,每行有N个数字,其中1表示可以走,0表示死路。接下来两行分别表示悟空和师傅所在洞穴坐标和传送门所在洞穴坐标。

输入:如果悟空他们可以成功走到传送门空间就输出YES,否则就输出 No。

样例输入:

  1. 5
  2. 1 0 0 1 0
  3. 1 1 1 1 1
  4. 1 0 1 0 0
  5. 1 0 1 1 1
  6. 0 1 0 1 0
  7. 4 4
  8. 2 1

样例输出:

YES

代码实现:

  1. #include<iostream>
  2. using namespace std;
  3. int dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};//遍历方向
  4. int n;//存储地图
  5. int G[1001][1001],vis[1001][1001];//G存储地图,vis标记是否被搜索过
  6. bool f=false;//存储是否找到传送门
  7. int sx,sy,cx,cy;
  8. void dfs(int x,int y){
  9. if(x==cx&&y==cy){
  10. cout<<"YES"<<endl;
  11. f=true;
  12. return ;
  13. }
  14. for(int i=0;i<4;i++){
  15. int xx=x+dx[i];
  16. int yy=y+dy[i];
  17. if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&G[xx][yy]!=0&&vis[xx][yy]==0){
  18. vis[xx][yy]=1;
  19. dfs(xx,yy);
  20. vis[xx][yy]=0;
  21. }
  22. }
  23. }
  24. int main(){
  25. cin>>n;
  26. for(int i=1;i<=n;i++){
  27. for(int j=1;j<=n;j++){
  28. cin>>G[i][j];
  29. }
  30. }
  31. cin>>sx>>sy;
  32. cin>>cx>>cy;
  33. if(sx==cx&&cy==sy){
  34. cout<<"YES"<<endl;
  35. return 0;
  36. }
  37. vis[sx][sy]=1;
  38. dfs(sx,sy);
  39. if(f==false){
  40. cout<<"NO"<<endl;
  41. }
  42. return 0;
  43. }


 路径版:

样例输入:

  1. 5
  2. 1 0 0 1 0
  3. 1 1 1 1 1
  4. 1 0 1 0 0
  5. 1 0 1 1 1
  6. 0 1 0 1 0
  7. 4 4
  8. 2 1

 样例输出:

(4,4)->(4,3)->(3,3)->(2,3)->(2,2)->(2,1)

 代码实现:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=101;
  4. int n;
  5. int x,y,cx,cy;
  6. int G[N][N],vis[N][N];
  7. int A[300][3];
  8. bool f=false;
  9. int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
  10. void dfs(int x,int y,int d){
  11. if(x==cx&&y==cy){
  12. f=true;
  13. for(int i=0;i<d-1;i++){
  14. cout<<"("<<A[i][0]<<","<<A[i][1]<<")->";
  15. }
  16. cout<<"("<<cx<<","<<cy<<")"<<endl;
  17. return;
  18. }
  19. for(int i=0;i<4;i++){
  20. int xx=x+dx[i];
  21. int yy=y+dy[i];
  22. if(xx>=1&&yy>=1&&xx<=n&&yy<=n&&G[xx][yy]==1&&vis[xx][yy]==0){
  23. vis[xx][yy]=1;
  24. A[d][0]=xx;
  25. A[d][1]=yy;
  26. dfs(xx,yy,d+1);
  27. vis[xx][yy]=0;
  28. }
  29. }
  30. }
  31. int main(){
  32. cin>>n;
  33. for(int i=1;i<=n;i++){
  34. for(int j=1;j<=n;j++){
  35. cin>>G[i][j];
  36. }
  37. }
  38. cin>>x>>y>>cx>>cy;
  39. if(x==cx&&y==cy){
  40. cout<<"YES"<<endl;
  41. return 0;
  42. }
  43. else{
  44. vis[x][y]=1;
  45. A[0][0]=x;
  46. A[0][1]=y;
  47. dfs(x,y,1);
  48. if(!f) cout<<"NO"<<endl;
  49. }
  50. return 0;
  51. }

【题目三:西游记之海域分块】

问题描述:

最近天气炎热,人鱼王国水位下降陆地露出海面,把王国分成了几个部分,国王的命令无法传达给公民,让红烧鱼国王感觉非常苦恼,所以国王想要请悟空帮忙给各个水域传递一个消息。虽然人鱼王国不大,但是如果悟空每个地方都去一次就会耽误很长时间,影响取经大业,所以悟空决定先计算一下陆地把人鱼王国分成了几部分。输入:第一行包合两个正整数N和M(1<N,M<30)表示人鱼王国的长和宽,下面是一个N行M列的二维数组,其中1表示陆地,0表示海水。

输入:一个整数a,表示陆地把海域分成的份数(斜着方向不算连通)。

样例输入:

  1. 5 5
  2. 1 0 0 1 0
  3. 0 1 0 0 1
  4. 1 0 1 0 0
  5. 1 0 0 1 1
  6. 0 1 0 1 0

样例输出:

6

核心思路:
从第一行开始从左向右开始遍历,如果当前位置是0,就从当前位置开始向四周深搜,把相连的0都变成1

  1. #include<iostream>
  2. using namespace std;
  3. int n,m;
  4. int G[1001][1001];
  5. int dx[5]={1,0,-1,0},dy[5]={0,1,0,-1};
  6. void dfs(int x,int y){
  7. for(int i=0;i<4;i++){
  8. int xx=x+dx[i];
  9. int yy=y+dy[i];
  10. if(xx>=0&&xx<n&&yy>=0&&yy<n&&G[xx][yy]==0){
  11. G[xx][yy]=1;
  12. dfs(xx,yy);
  13. }
  14. }
  15. }
  16. int main(){
  17. cin>>n>>m;
  18. for(int i=0;i<n;i++){
  19. for(int j=0;j<m;j++){
  20. cin>>G[i][j];
  21. }
  22. }
  23. int res=0;
  24. for(int i=0;i<n;i++){
  25. for(int j=0;j<m;j++){
  26. if(G[i][j]==0){
  27. G[i][j]=1;
  28. dfs(i,j);
  29. res++;
  30. }
  31. }
  32. }
  33. cout<<res<<endl;
  34. return 0;
  35. }

【题目四: 国王的神器 】

问题描述:

红烧鱼国王拿出了祖传神器(水管),他可以使斜对角的海域连通,这样悟空就可以少通知一些地方了,真是个不错东西,我们-起来计算一下使用神器后,悟空需要通知几个海域。
输入:第一行包含两个正整数N和M(1<N,M<30)表示人鱼王国的长和宽,下面是
一个N行M列的二维数组,其中1表示陆地,0表示海水。
输入:一个整数a表示陆地把海域分成的份数(斜着方向连通)。


样例输入:

  1. 5 5
  2. 1 0 0 1 0
  3. 0 1 0 0 1
  4. 1 0 1 0 0
  5. 1 0 0 1 1 
  6. 0 1 0 1 0   

样例输出:

2

代码实现:

  1. #include<iostream>
  2. using namespace std;
  3. int G[1001][1001];
  4. int n,m,mins=2147483647,sum=0;
  5. int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
  6. void dfs(int x,int y){
  7. for(int dx=-1;dx<=1;dx++){
  8. for(int dy=-1;dy<=1;dy++){
  9. int xx=x+dx;
  10. int yy=y+dy;
  11. if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&G[xx][yy]==0){
  12. G[xx][yy]=1;
  13. dfs(xx,yy);
  14. }
  15. }
  16. }
  17. }
  18. int main(){
  19. cin>>n>>m;
  20. for(int i=1;i<=n;i++){
  21. for(int j=1;j<=m;j++){
  22. cin>>G[i][j];
  23. }
  24. }
  25. int res=0;
  26. for(int i=1;i<=n;i++){
  27. for(int j=1;j<=m;j++){
  28. if(G[i][j]==0){
  29. if(G[i][j]==0){
  30. G[i][j]=1;
  31. dfs(i,j);
  32. res++;
  33. }
  34. }
  35. }
  36. }
  37. cout<<res<<endl;
  38. return 0;
  39. }

【题目五:唐僧去哪儿】

问题描述:

历经磨难,悟空和三藏终于逃出魔爪,正准备去找沙僧等人,问题又来了。他们的位置离沙僧比较远,现在有一副地图。地图每个位置都有一个数字表示经过这个位置需要用的时间(本来就一个筋斗云的事,带着师傅就是麻烦)

地图如下:

 1  6  6  6 

15  7  6  6 

15  3  6  6 

15 15 1  1 

输入:第一行包含两个正整数N和M(1<N,M<30)表示人鱼王国的长和宽下面一行包含4个整数,前两个数表示猴哥和师傅的位置,后面两个数表示沙僧位置,最后是一个N行M列的二维数组,每个数字表示走当前位置需要用的时间。

输出:一个整数,表示最短时间。

样例输入: 

  1. 4 4 
  2. 1 1 4 4 
  3. 1 6 6 6 
  4. 15 7 6 6 
  5. 15 3 6 6 
  6. 15 15 1 1 


样例输出:

25

代码实现: 

  1. #include<iostream>
  2. using namespace std;
  3. int n,m,sx,sy,cx,cy,sum=0;
  4. int mins=2147483647; //设置最小值
  5. int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
  6. int G[1001][1001],vis[1001][1001];
  7. void dfs(int x,int y){
  8. vis[x][y]=1;
  9. sum+=G[x][y];
  10. if(x==cx&&y==cy){
  11. mins=(sum<mins)?sum:mins; //三目运算,如果总和为最小则更新最小值
  12. vis[x][y]=0;//回溯
  13. sum-=G[x][y];//及时更新总和的值
  14. return;
  15. }
  16. for(int i=0;i<4;i++){
  17. int xx=x+dx[i];
  18. int yy=y+dy[i];
  19. if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&vis[xx][yy]==0){
  20. dfs(xx,yy);
  21. }
  22. }
  23. sum-=G[x][y]; //回溯
  24. vis[x][y]=0; //及时更新总和的值
  25. return;
  26. }
  27. int main(){
  28. cin>>n>>m>>sx>>sy>>cx>>cy;
  29. for(int i=1;i<=n;i++){
  30. for(int j=1;j<=m;j++){
  31. cin>>G[i][j];
  32. }
  33. }
  34. dfs(sx,sy);
  35. cout<<mins;
  36. return 0;
  37. }

题目六:红与黑


问题描述: 

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一
块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多
少块黑色的瓷砖。
输入:第一行是两个整数W和H,分别表示×方向和y方向瓷砖的数量。W和H 都不超过20。在接下来的H行中,每行包括W个字符。每个字符表示一块瓷砖的颜色
规则如下:

  1. '.'黑色的瓷砖;
  2. '#'白色的瓷砖;
  3. '@’:黑色的瓷砖并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。

输出:对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数
时包括初始位置的瓷砖)。

样例输入:

  1. 6 9
  2. ....#.
  3. .....#
  4. ......
  5. ......
  6. ......
  7. ......
  8. ......
  9. #@...#
  10. .#..#.

样例输入:

45

代码实现: 

  1. #include<iostream>
  2. using namespace std;
  3. int a[1001][1001],book[1001];//a为每件工作的收益值,book为是否被分配工作
  4. int n;//需要n个人来完成
  5. int maxl=0;
  6. int dfs(int step,int t){ //step为第几个工作,t为已得的收益
  7. for(int i=1;i<=n;i++){ //表示1-n个人
  8. if(!book[i]){
  9. book[i]=1;
  10. t+=a[step][i];
  11. if(step<n) dfs(step+1,t);
  12. if(t>maxl) maxl=t;//取最大值
  13. t-=a[step][i];//回溯
  14. book[i]=0;
  15. }
  16. }
  17. }
  18. int main(){
  19. cin>>n;
  20. for(int i=1;i<=n;i++){
  21. for(int j=1;j<=n;j++){
  22. cin>>a[i][j];
  23. }
  24. }
  25. dfs(1,0);
  26. cout<<maxl<<endl;
  27. return 0;
  28. }

题目七:最多的字母


问题描述:

给出一个R*S的大写字母矩阵,一开始的位置为左上角,你可以向上下左右四个方向移动,并且不能移向曾经出现过的字母。问最多可以经过几个字母。(单次的一条路线不能重复出现相同的字母。) 


样例输入: 

  1. 3 6
  2. HFDFFB
  3. AJHFDH
  4. DGAGEH

样例输出: 

6

问题分析:

fb5651fb3fef420e8cc6c39b274d9782.jpeg

代码实现: 

  1. #include<iostream>
  2. using namespace std;
  3. int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
  4. bool vis[30];
  5. int r,s,sum=1,cnt=1;
  6. char map[1001][1001];
  7. int dfs(int x,int y){
  8. if(cnt>sum) sum=cnt;
  9. vis[map[x][y]-'A']=1;
  10. for(int i=0;i<4;i++){
  11. int xx=x+dx[i];
  12. int yy=y+dy[i];
  13. if(xx>=1&&xx<=r&&yy>=1&&yy<=s&&!vis[map[xx][yy]-'A']){
  14. cnt++;
  15. dfs(xx,yy);
  16. vis[map[xx][yy]-'A']=0;
  17. cnt--;
  18. }
  19. }
  20. }
  21. int main(){
  22. cin>>r>>s;
  23. for(int i=1;i<=r;i++){
  24. for(int j=1;j<=s;j++){
  25. cin>>map[i][j];
  26. }
  27. }
  28. dfs(1,1);
  29. cout<<sum<<endl;
  30. return 0;
  31. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/533682
推荐阅读
相关标签
  

闽ICP备14008679号