用dfs和bfs解决迷宫问题
小明走迷宫
输入
输入多组测试数据。
对于每组数据,第一行是两个数字n和m,表示该阵为nm大小(0<m,n<=10,n为行,m为列)。
接下来是一个mn的矩阵表示这个阵。
其中0为该阵中可走的路,1为墙(不可走),2为小明的位置,3为出口的位置。
小明只有四个可行的行走方向:即上、下、左、右。
输出
如果小明可以逃离,输出Yes,反之输出No
输入样例
8 7
1 1 1 1 1 1 3
1 0 0 0 0 0 0
1 0 1 1 1 1 1
1 0 0 0 1 1 1
1 1 1 0 0 0 1
1 0 0 0 1 0 1
1 0 1 1 1 0 1
2 0 1 1 1 0 0
4 4
0 3 1 2
1 1 1 0
0 0 1 0
0 0 0 0
输出样例
Yes
No
一、用dfs解决
首先解决输入问题,就直接上代码
//关于输入部分的代码
while(scanf("%d%d",&n,&m)!=EOF){//多组测试数据
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==2){//入口
sx=i;
sy=j;
}
if(a[i][j]==3){//出口
sx=i;
sy=j;
}
}
}
}
接着就开始用dfs解决问题,dfs的思路就是朝一个方向一直搜,碰壁后就返回到上一个节点朝另一个方向搜索,直到搜到最后的目的地。因此很容易想到,使用一个变量来判断是否能到终点,然后用dfs的思路进行搜索。
解决一些写dfs函数前的问题
//首先定义一些全局变量与数组进行处理,这里以行增加为x方向增加,列增加为y方向增加
int a[12][12];//存储迷宫
int b[12][12];//存储是否走过迷宫某个位置
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; //四个方向坐标变化(右下左上)
int flag=0;//判断是否能到终点
进入正题,dfs函数的完成
//关于dfs函数的代码
void dfs(int x,int y,int p,int q){//(x,y)为当前坐标,(p,q)为终点坐标
int tx,ty,k;
if(a[x][y]==3){
flag=1;//走出迷宫
return;//返回上一节点(其实可以使函数结束,但很多问题都需要返回
}
for(k=0;k<4;k++){//四个方向
tx=x+next[k][0];//下一个位置的x坐标
ty=y+next[k][1];//下一个位置的y坐标
if(tx<1||ty<1||tx>n||ty>m) continue;//超出迷宫范围
if((a[tx][ty]==0||a[tx][ty]==3)&&b[tx][ty]==0){
//第一个判断是否能走,第二个判断是否走过
b[tx][ty]=1;//不能走回头路了
dfs(tx,ty,p,q);//递归
b[tx][ty]=0;//要回到这尝试下一个方向,这个点标记取消
}
}
return;//死路,返回上一节点
}
完成了dfs函数的代码后,整合一下就可得到完整的代码了
//完整代码
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int a[12][12];
int b[12][12];
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n,m,flag=0;
void dfs(int x,int y,int p,int q)
{
int tx,ty,k;
if(a[x][y]==3){
flag=1;
return;
}
for(k=0;k<4;k++){
tx=x+next[k][0];
ty=y+next[k][1];
if(tx<1||ty<1||tx>n||ty>m) continue;
if((a[tx][ty]==0||a[tx][ty]==3)&&b[tx][ty]==0){
b[tx][ty]=1;
dfs(tx,ty,p,q);
b[tx][ty]=0;
}
}
return;
}
int main()
{
int i,j;
int sx,sy,ex,ey;
for(i=1;i<=11;i++){//把迷宫先全变成有墙(容易理解)
for(j=1;j<=11;j++){
a[i][j]=1;
}
}
while(scanf("%d%d",&n,&m)!=EOF){
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==2){
sx=i;
sy=j;
}
if(a[i][j]==3){
ex=i;
ey=j;
}
}
}
b[sx][sy]=1;//起点走过了
dfs(sx,sy,ex,ey);
if(flag) printf("Yes\n");
else printf("No\n");
for(i=1;i<=11;i++){
for(j=1;j<=11;j++){
a[i][j]=1;
b[i][j]=0;
}
}
flag=0;
}
return 0;
}
二、用bfs解决
输入代码部分与准备部分代码同上,bfs的思路是寻找这个位置再走一步能到哪些位置,将这些位置入队列,然后下一个能走到的位置再重复进行这些操作。
直接上代码(重复部分没有标注解释)
#include<stdio.h>
#include<string.h>
int a[12][12];
int b[12][12];
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct note//定义一个队列
{
int x;
int y;
};
int main()
{
int i,j,k;
int n,m;
int sx,sy,ex,ey;
int tx,ty;
struct note que[120];
for(i=1;i<=13;i++){
for(j=1;j<=11;j++){
a[i][j]=1;
}
}
while(scanf("%d%d",&n,&m)!=EOF){
int head=1,tail=1,flag=0;//定义队列头,队列尾
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==2){
sx=i;
sy=j;
}
if(a[i][j]==3){
ex=i;
ey=j;
}
}
}
que[tail].x=sx;//开始横坐标入队
que[tail].y=sy;//开始纵坐标入队
tail++;
b[sx][sy]=1;
while(head<tail){//还有某个位置可以继续拓展
for(k=0;k<4;k++){
tx=que[head].x+next[k][0];
ty=que[head].y+next[k][1];
if(tx<1||ty<1||tx>n||ty>m) continue;
if((a[tx][ty]==0||a[tx][ty]==3)&&b[tx][ty]==0){
b[tx][ty]=1;
que[tail].x=tx;//成立的点入队
que[tail].y=ty;
tail++;//队尾推进
//这里不需要再将这点清零,因为不用回来
}
if(a[tx][ty]==3){
flag=1;
break;
}
}
if(flag==1){
break;
}
head++;
}
if(flag) printf("Yes\n");
else printf("No\n");
for(i=0;i<=13;i++){
for(j=0;j<=13;j++){
a[i][j]=1;
b[i][j]=0;
}
}
flag=0;
}
return 0;
}
至此,结束,欢迎各位指正