可以使用BFS或者DFS方法解决的迷宫问题!

题目如下:

kotori在一个n*m迷宫里,迷宫的最外层被岩浆淹没,无法涉足,迷宫内有k个出口。kotori只能上下左右四个方向移动。她想知道有多少出口是她能到达的,最近的出口离她有多远?

输入描述:

第一行为两个整数n和m,代表迷宫的行和列数 (1≤n,m≤30)

后面紧跟着n行长度为m的字符串来描述迷宫。'k'代表kotori开始的位置,'.'代表道路,'*'代表墙壁,'e'代表出口。保证输入合法。

输出描述:

若有出口可以抵达,则输出2个整数,第一个代表kotori可选择的出口的数量,第二个代表kotori到最近的出口的步数。(注意,kotori到达出口一定会离开迷宫)

若没有出口可以抵达,则输出-1。
示例1

输入

复制

6 8
e.*.*e.*
.**.*.*e
..*k**..
***.*.e*
.**.*.**
*......e

输出

复制

2 7

说明

可供选择坐标为[4,7]和[6,8],到kotori的距离分别是8和7步。

DFS解决如下:
 #include<iostream>
#include<string.h>
using namespace std;
char map[][];
int use[][];
int dir[][] = {{,},{,},{,-},{-,}}; //上下左右四个方向
int minn = ; int pan(int x,int y)
{
if( <= x && x <= && <= y && y <= && (map[x][y] == '.' || map[x][y]=='k')) return ;
else return ;
} void dfs(int x,int y,int step)
{
// 递归程序,必须要设置整个程序的出口,在dfs中,即当走到迷宫出口处即可结束程序
if(map[x][y] == 'e')
{
cout<<"success"<<endl;
if(step < minn) minn = step;
return;
}
for(int i = ; i < ; i++)
{
if(pan(x,y) && use[x][y] != )
{
use[x][y] = ;
cout<<"dd";
cout<<" "<<map[x+dir[i][]][y+dir[i][]]<<endl;
dfs(x+dir[i][],y+dir[i][],step+);
use[x][y] = ;
}
} }
int main()
{
int n;
int m;
cin >> n >> m;
// 4,5行已经定义了map和use数据,所以在此处不必int map[n][m],直接map[n][m]即可,否则报错
map[n][m];
use[n][m];
memset(use,,sizeof(use));
int x_start = ;
int y_start = ;
int step = ;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cin >> map[i][j];
if(map[i][j] == 'k')
{
x_start = i;
y_start = j;
}
}
}
cout<<x_start<<" "<<y_start<<endl;
dfs(x_start, y_start, step);
cout<<"最小步数"<<minn<<endl;
}

BFS解决如下:

(1)自己写的有缺陷的代码:

 #include<iostream>
#include<queue>
#include<string.h>
using namespace std;
char map[][];
int vis[][];
int use[][];
int m,n;
int x_start,y_start;
queue<int> que;
int dir[][] = {{,},{,-},{,},{-,}};
int cnt = ;
int mi = ; int pan(int x,int y)
{
if( <= x && x <= n- && <= y && y <= m - &&map[x][y] != '*') return ;
else return ;
} void bfs(int x,int y)
{
int x1 = x;
int y1 = y;
while(!que.empty())
{
vis[x1][y1] = ;
x1 = que.front();
que.pop();
y1 = que.front();
que.pop();
cout<<"x1:"<<x1<<" "<<"y1:"<<y1<<endl;
if(map[x1][y1] == 'e')
{
if(use[x1][y1] == )
{
cnt++;
use[x1][y1]=;
}
continue;
} for(int i = ; i < ; i++)
{
int xx = x1 + dir[i][];
int yy = y1 + dir[i][];
if(pan(xx,yy) && vis[xx][yy] == )
{
cout<<"dd"<<endl;
cout<<xx<<" "<<yy<<endl;
que.push(xx);
que.push(yy);
vis[xx][yy] = ;
}
}
}
} int main()
{
memset(vis,,sizeof(vis));
memset(use,,sizeof(use));
cin >> n >> m;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cin >> map[i][j];
if(map[i][j] == 'k')
{
x_start = i;
y_start = j;
}
}
}
que.push(x_start);
que.push(y_start);
bfs(x_start,y_start);
cout<<cnt<<endl; }

对于每个点每个状态我采用的是直接利用队列记录他们的坐标值,而不是如AC代码一样利用结构体记录每个点的每个状态。所以导致我整个程序还是存在很大的缺陷,例如求最短路径的时候就比较困难。

所以对于BFS的题目,强烈建议把每个点每个状态先用结构体表示,然后利用队列记录这些结构体即可。

(2)AC代码

 #include<bits/stdc++.h>
using namespace std;
char a[][];
bool usd[][];
int Move[][]={{,},{,},{-,},{,-}};
struct now
{
int x,y,dis;
};
queue<now>q;
int main()
{
int n,m,cnt=;
scanf("%d%d",&n,&m);
now s;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
cin>>a[i][j];
if(a[i][j]=='k')
{
s.x=i;
s.y=j;
s.dis=;
}
}
q.push(s);
int ans=;
while(!q.empty())
{
now Now=q.front();
q.pop();
if(a[Now.x][Now.y]=='e')
{
if(!usd[Now.x][Now.y])
{
++cnt;
ans=min(ans,Now.dis);
}
usd[Now.x][Now.y]=true;
continue; //到达出口"e"处就必须跳过一下步骤,不能在对出口点“e”进行下面的扩展步骤(上下左右)
}
usd[Now.x][Now.y]=true;
for(int i=;i<;++i)
{
int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
{
now t;
t.x=xx;
t.y=yy;
t.dis=d+;
q.push(t);
}
}
}
if(!cnt)
return !printf("-1\n");
printf("%d %d\n",cnt,ans);
return ;
}

 带路径输出的BFS(路径的输出主要依靠递归程序,记录每个点的结构体还需要记录每个点的前驱节点的坐标)

 #include<bits/stdc++.h>
using namespace std;
char a[][];
bool usd[][];
int Move[][]={{,},{,},{-,},{,-}};
struct now
{
int x,y,dis,pre_x,pre_y;
};
queue<now>q;
now buf[];
int count1 = ; void print(int x,int y)
{
int temp;
for(int i = ; i < count1; i++)
{
if(buf[i].x == x && buf[i].y == y) temp = i;
}
if(x == - && y == -) return;
else
{
print(buf[temp].pre_x,buf[temp].pre_y);
cout<<"("<<x<<","<<y<<")"<<endl;
}
} int main()
{
int n,m,cnt=;
scanf("%d%d",&n,&m);
now s;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
cin>>a[i][j];
if(a[i][j]=='k')
{
s.x=i;
s.y=j;
s.pre_x = -;
s.pre_y = -;
s.dis=;
}
}
q.push(s);
int ans=;
while(!q.empty())
{
now Now=q.front();
buf[count1++] = Now;
q.pop();
if(a[Now.x][Now.y]=='e')
{
if(!usd[Now.x][Now.y])
{
++cnt;
ans=min(ans,Now.dis);
usd[Now.x][Now.y]=true;
print(Now.x,Now.y);
}
continue;
}
usd[Now.x][Now.y]=true;
for(int i=;i<;++i)
{
int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
{
now t;
t.x=xx;
t.y=yy;
t.pre_x = Now.x;
t.pre_y = Now.y;
t.dis=d+;
q.push(t);
}
}
}
if(!cnt)
return !printf("-1\n");
printf("%d %d\n",cnt,ans);
// for(int i = 0; i < count1; i++)
// {
// cout<<buf[i].x<<" "<<buf[i].y<<" "<<buf[i].pre_x<<" "<<buf[i].pre_y<<endl;
// }
return ;
}

利用dfs解决最大连通块问题!

题目描述

农场主约翰的农场在最近的一场风暴中被洪水淹没,这一事实只因他的奶牛极度害怕水的消息而恶化。

然而,他的保险公司只会根据他农场最大的“湖”的大小来偿还他一笔钱。

农场表示为一个矩形网格,有N(1≤N≤100)行和M(1≤M≤100)列。网格中的每个格子要么是干的,

要么是被淹没的,而恰好有K(1≤K≤N×M)个格子是被淹没的。正如人们所期望的,一个“湖”有一个

中心格子,其他格子通过共享一条边(只有四个方向,对角线不算的意思)与之相连。任何与中央格子共享一条边或与中央格

子相连的格子共享一条边的格子都将成为湖的一部分。

输入描述:

第一行有三个整数N,M,K,分别表示这个矩形网格有N行,M列,K个被淹没的格子。

接下来K行,每一行有两个整数R,C。表示被淹没的格子在第R行,第C列。

输出描述:

输出最大的“湖”所包含的格子数目

输入

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

输出

4
 #include<iostream>
using namespace std;
int map[][];
int vis[][] = {};
int used[][] = {};
int dir[][] = {{,},{-,},{,},{,-}};
int n,m,k;
int cnt = ;
int maxx = -;
int pan(int x,int y)
{
if(map[x][y] == && <= x && x <= n- && y <= m- && y >= && vis[x][y] == && used[x][y]==)
{
return ;
}
else return ;
} void dfs(int x,int y,int c) //连通块问题就不像迷宫问题有递归出口!!!!
{
vis[x][y] = ;
// cout<<x<<" "<<y<<" dd"<<endl;
for(int i = ; i < ; i++)
{
int xx = x + dir[i][];
int yy = y + dir[i][];
if(pan(xx,yy))
{
// cout<<xx<<" "<<yy<<endl;
vis[xx][yy] = ;
used[xx][yy] = ; // used数组是防止多次记录连通块!
cnt++;
c = cnt; // 这一块必须注意,不能直接传入cnt,因为递归函数是放在栈中,倘若传入cnt,递归函数出栈时,cnt的值也会变化,所以用c代替cnt.
dfs(xx,yy,c);
vis[xx][yy] = ;
}
}
} int main()
{
cin >> n >> m >> k;
map[n][m];
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++) map[i][j] = ;
}
for(int i = ; i < k; i++)
{
int x,y;
cin >> x >> y;
map[x-][y-] = ;
}
// for(int i = 0; i < n; i++) 打印整个地图
// {
// for(int j = 0; j < m; j++)
// {
// cout<<map[i][j];
// }
// cout<<endl;
// }
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cnt = ;
if(map[i][j] == )
{
dfs(i,j,cnt);
if(cnt > maxx) maxx = cnt;
}
}
}
cout<<maxx<<endl; }

本题总结:

1.利用dfs解决连通块问题与利用dfs解决迷宫问题存在一定的区别:

(1)迷宫问题有固定的入口或者出口,而连通块问题就没有所谓的出口或者入口,它需要遍历map[][]数组中的每个元素!

有关dfs、bfs解决迷宫问题的个人见解的更多相关文章

  1. 用BFS解决迷宫问题

    在一个n*n的矩阵里走,从原点(0,0)開始走到终点(n-1,n-1),仅仅能上下左右4个方向走.仅仅能在给定的矩阵里走,求最短步数. n*n是01矩阵,0代表该格子没有障碍.为1表示有障碍物. in ...

  2. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  3. [LeetCode] BFS解决的题目

    一.130  Surrounded Regions(https://leetcode.com/problems/surrounded-regions/description/) 题目: 解法: 这道题 ...

  4. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  5. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  6. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  7. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

  8. HDU 4771 (DFS+BFS)

    Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...

  9. DFS/BFS视频讲解

    视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...

随机推荐

  1. 实现:API实现创建用户并且添加至管理员

    参考文章:https://www.cnblogs.com/17bdw/p/6790197.html#_label0 利用的API函数: 1.NetUserAdd 2.NetLocalGroupAddM ...

  2. linux查看反汇编

    生成反汇编文件 gcc xxx.c -g -o a.out objdump a.out -dSsx > file 调试的时候查看反汇编: gdb a.out ...layout asm 参考博文 ...

  3. kuma kong 团队开发的可视化&&安全的service mesh

    最近service mesh 的开源产品是越来越多了,好多团队都开源了自己的解决方案 maesh 最近kong 团队也开源了自己的service meshkuma 一张参考图 说明 kuma 没有基于 ...

  4. RFM客户价值分类

    # 自定义好的包,亲测可用 原数据和代码思想来自以下网址 # https://github.com/joaolcorreia/RFM-analysis import datetime as dt im ...

  5. vue单项数据流

    当父组件给子组件传递数据的时候,子组件只能读取,不能改写.因为如果子组件改变父组件传递过来的数据时会造成数据流难以理解.

  6. GoCN每日新闻(2019-10-28)

    GoCN每日新闻(2019-10-28) 1. 理解和攻击Go DSA验证漏洞 https://paul.querna.org/articles/2019/10/24/dsa-verify-poc/2 ...

  7. django 下载文件,指定文件中文名称

    Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件.Content-disposition其实可以控制用户请求所得的内容存为一个 ...

  8. Java8中HashMap扩容算法小计

    Java8的HashMap扩容过程主要就是集中在resize()方法中 final Node<K,V>[] resize() { // ...省略不重要的 } 其中,当HashMap扩容完 ...

  9. FZU Monthly-201906 获奖名单

    FZU Monthly-201906 获奖名单 冠军: 空缺 一等奖: 陈金杰 S031702334 空缺 二等奖: 黄海东 S031702647 吴宜航 S031702645 蔡煜晖 S111801 ...

  10. webpack配置css浏览器前缀

    webpack打包时,css自动添加浏览器前缀.我们需要用到一个Loader:postcss-loader,和一个插件:autoprefixer 安装 npm i postcss-loader aut ...