经典例子——解救小哈(深度搜索)
【题目描述】
有一天,小哈一个人去玩迷宫。但是方向感很不好的小哈很快就迷路了。小哼得知后便要去解救无助的小哈。小哼当然是有备而来,已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈。问题就此开始了……
迷宫由n行m列的单元格组成(n和m都小于等于50),每个单元格要么是空地(用0表示),要么是障碍物(用1表示)。你的任务是帮助小哼找到一条从迷宫的起点(x,y)通往小哈所在位置(q,p)的最短路径。注意障碍物是不能走的,当然小哼也不能走到迷宫之外。
【输入】
首先输入n和m,代表二维数组(迷宫)的行和列。
接着输入一个二维数组。
最后输入迷宫的起点坐标(x,y)和小哈所在的位置(q,p)。
【输出】
小哼从起点通往小哈位置的最短路径。
样例输入
5 4
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
样例输出
7
上面这个题就是简单的用深度优先搜索来解决的迷宫问题,就是下面这个代码的进阶版,即二维数组的版本,只要了解下面代码原理,就可以由点及面,解决这个简单的走迷宫问题。
#include <stdio.h>
int a[10],book[10],n;
void dfs(int step) //step表示站在第几个盒子前面
{
int i;
if(step==n+1) //如果站在第n+1个盒子面前,则表示前n个盒子已经放好扑克牌了
{
//输出一种排序(1~n号盒子的扑克牌编号)
for(i=1;i<=n;i++)
{
printf("%d",a[i]);
}
printf("\n");
return ; //返回之前的一步(最近一次调用dfs函数的地方)
}
for(i=1;i<=n;i++)
{
if(book[i]==0)
{
a[step]=i ; //将i号扑克牌放入第step个盒子中
book[i]=1; //将book[i]设为1,表示i号扑克牌已经不在手
dfs(step+1); //这里通过函数的递归调用来实现
book[i]=0; //将刚才尝试的扑克牌收回,才能进行下一次尝试
}
}
}
int main()
{
scanf("%d",&n); //输入n为1~9的整数
dfs(1); //首先站到1号盒子面前
getchar();
return 0;
}
迷宫问题基本原理代码
#include <stdio.h>
int min=999;
int p,q; //终点位置
int step;
int a[100][100],book[100][100]; //1表示空地,2表示障碍物
void dfs(int x,int y,int step)
{
if(x==p&&y==q)
{
if(step<min)
{
min=step;
return;
}
}
if(a[x][y+1]==1&&book[x][y+1]==0)
{
book[x][y+1]=1;
dfs(x,y+1,step+1);
book[x][y+1]=0;
}
if(a[x+1][y]==1&&book[x+1][y]==0)
{
book[x+1][y]=1;
dfs(x+1,y,step+1);
book[x+1][y]=0;
}
if(a[x][y-1]==1&&book[x][y-1]==0)
{
book[x][y-1]=1;
dfs(x,y-1,step+1);
book[x][y-1]=0;
}
if(a[x-1][y]==1&&book[x-1][y]==0)
{
book[x-1][y]=1;
dfs(x-1,y,step+1);
book[x-1][y]=0;
}
}
int main()
{
int start_x,start_y;
int m,n;
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]); //输入迷宫数字图形
scanf("%d%d%d%d",&start_x,&start_y,&p,&q);
dfs(start_x,start_y,0);
printf("%d",min);
}
这个代码dfs函数跟上面代码类似,就是由判断一个方向,转变为判断四个方向。代码设初始位置为x,y。右:(x,y+1),下:(x+1,y),左:(x,y-1),上:(x-1,y),当然也可以设成其他形式,主要看理解。同第一个代码一样,需要设一个book[]数组来判断是否走过,如果没走过并且不是死路,就可以进入,然后再if中再次调用dfs函数去走下一步,这就用到嵌套了,这是一步很巧妙的写法,如果到达了终点也可以通过这一层层的嵌套进行回溯,这也是为什么dfs函数后面将book又变成0,即未走过了。而再判断走的方向一般是按顺时针来的。
迷宫问题代码优化
下面代码是用循环将上面方向代码整合了。
#include <stdio.h>
int min=999;
int p,q; //终点位置
int step;
int a[100][100],book[100][100]; //1表示空地,2表示障碍物
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void dfs(int x,int y,int step)
{
if(x==p&&y==q)
{
if(step<min)
{
min=step;
return;
}
}
for(int k=0;k<=3;k++)
{
int tx,ty;
tx=x+dx[k];
ty=y+dy[k];
if(a[tx][ty]==1&&book[tx][ty]==0)
{
book[tx][ty]=1;
dfs(tx,ty,step+1);
book[tx][ty]=0;
}
}
}
int main()
{
int start_x,start_y;
int m,n;
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]); //输入迷宫数字图形
scanf("%d%d%d%d",&start_x,&start_y,&p,&q);
dfs(start_x,start_y,0);
printf("%d",min);
}