题目:少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。
下图 显示了一个迷阵的样例及李逍遥找到仙药的路线.
Input
输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于20。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义:
1) ‘@’:少年李逍遥所在的位置;
2) ‘.’:可以安全通行的方格;
3) ‘#’:有怪物的方格;
4) ‘*’:仙药所在位置。
当在一行中读入的是两个零时,表示输入结束。
Output
对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。
Sample
input
8 8 .@##...# #....#.# #.#.##.. ..#.###. #.#...#. ..###.#. ...#.*.. .#...### 6 5 .*.#. .#... ..##. ..... .#... ....@ 9 6 .#..#. .#.*.# .####. ..#... ..#... ..#... ..#... #.@.## .#..#. 0 0 |
output
10 8 -1 |
深度优先搜索算法(本题不适合,但还是可以做出正确结果,但是会超时 time limited)
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int v[50][50];
char mm[50][50];
int sx,sy=0;
int minn=99999999;
int m,n,x=0;
int dx[4]={1,-1,0,0};//向 下 右 左 上 四个方向移动
int dy[4]={0,0,1,-1};
int flag=0;//判断是否找到解药的标记
void dfs(int x,int y,int step)
{
/*for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++) //可以把这个注释解除看一看效果哟,可以清楚得看到代码的移动,1表示深搜寻找移动的方向
{
cout<<v[i][j]<<" ";
} cout<<endl;
} cout<<"***********************"<<endl; */
if(mm[x][y]=='*')
{
//如果找到了*,就标记1,意为已经找到
flag=1;
if(step<minn)//如果发现step比minn还要小,就将最小值替换为step,因为他题目要求找到解要所需要最小路径
{
minn=step;
}
return;
}
for(int i=0;i<4;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(tx<0||ty<0||tx>=m||ty>=n||v[tx][ty]||mm[tx][ty]=='#') //如果越界或者碰到墙,就暂停
{
continue;
}
v[tx][ty]=1;//将该点标记为1,已经到达
dfs(tx,ty,step+1);//进入深搜,步数+1
v[tx][ty]=0;//回退,恢复原来的路径
}
return ;
}
int main()
{
cin>>m>>n;//输入地图的大小
while(m&&n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>mm[i][j];//将地图导入数据
if(mm[i][j]=='@')
{
sx=i;sy=j;//记录出发点的位置为进入深搜做准备
}
}
}
v[sx][sy]=1;//进入前地图标记为1
dfs(sx,sy,0);//0表示步数,一开始从出发点,步数为走,为0
if(flag==1)//说明找到
{
cout<<minn<<endl;
}
else cout<<"-1"<<endl; //找不到,标记为-1
flag=0;
memset(v,0,sizeof(v)); //将mm和v二维数组全部恢复默认值0
memset(mm,0,sizeof(mm));
cin>>m>>n;
}
return 0;
}
广度优先搜索
#include<bits/stdc++.h>//bfs函数中,先建立自定义结构体stu的队列
//将出发点位置和步数0存到对象s1中,本代码中s1和s2用来不断模拟队首出队(s1)和入队(s2)
//将s1入队,判断队列是否为空,若不为空,队首出队
//以出队的位置为原点,向 右下左上 四个方向分别移动,
//先打比方,先向右移动一格,先判断原点右一格的位置是否满足“通路的条件” ,
//若不满足,continue回到for循环,继续向“下”的方向遍历
//若满足 ,则在v地图上标记v[tx][ty]=1,记录为已经走过 ,并将这个位置 称为结构体stu类型的 对象 s2
//当前位置s2和前个位置s1对比n+1,n是步数。 s2记录下当前位置
//再判断一下这个位置是否为解药 ‘*’ 对应的位置,
//如果是,则记录更新从出发点到达这个位置所需要的最小步数,如果不是解药的位置,则判断完毕,
//接下来将s2压入队列,继续for循环从 原点 向下一个方向去重复查找
using namespace std;
int v[100][100];//v地图初始全为0,0意为为走过,1为已经走过
char mm[100][100];//v地图初始全为0,‘*’为解药,‘#’为墙,‘.’为通路
int dx[4]={1,0,-1,0};//dx,dy这个数组建立,是为了向4个方向去移动
int dy[4]={0,1,0,-1};//在bfs中自己感受它是如何向4个方向寻找的
int minn=9999;
int m,n,s=0;//m行,n列
struct stu{ //stu是自定义结构体的名字
int sx,sy,n; //创建这个结构体为后续做铺垫
}s1,s2;//s1表示当前位置,s2表示下一个位置
void bfs(int xx,int yy)//广搜
{//先创建一个存储结构体的队列,中间stu表面这个是一个存储stu这个类型结构体的队列
queue<stu>ss;//申请队列
int tx,ty;
s1.n=0;s1.sx=xx;s1.sy=yy;
ss.push(s1);//将出发点的结构体(包含坐标和步数)压入队列
while(!ss.empty())//只要队列不是空,就依次反复循环地执行队列,也是本广搜的核心部分
{ s1=ss.front();//(将队首元素出队),表示的是队首元素,赋值给s1,
ss.pop();//将队首的那个弹出(完成出队删除操作)
for(int i=0;i<4;i++)//向4个方向依次遍历
{
tx=s1.sx+dx[i];
ty=s1.sy+dy[i];
if(tx<=0||ty<=0||tx>n||ty>m||v[ty][tx]==1||mm[ty][tx]=='#') continue;//判断是否超出地图或者碰到“墙”,如果是就换一个方向(continue)
v[ty][tx]=1;//如果上面条件不符合,则是通路,可以走,就在v地图中标记为1,记为已经走过
//步数+1
s2.n=s1.n+1;//s2记为下一个方向的位置,s1是原来的位置
s2.sx=tx;
s2.sy=ty;
if(mm[ty][tx]=='*')//碰到解药,不断比较当前步数与最小值的步数,取最小值
{
minn=min(minn,s2.n);
s=1;//找到结果,s记为1
} ss.push(s2);//每次s1到s2移动到下一个位置后,最后都要将s2的压入队列当中
}
}
}
int main()
{
int x1,y1=0;
cin>>n>>m;//输入地图的大小
while(n&&m)//只要不出现0,就能执行
{
for(int i=1;i<=m;i++)//将地图输入到这个mm地图当中
{
for(int j=1;j<=n;j++)
{
cin>>mm[i][j];
if(mm[i][j]=='@')//记录出发点的位置
{
x1=j,y1=i;
}
}
}//bfs肯定要把出发位置压入队列,在所有压入队列前面都要在v地图上标记为已经走过
v[y1][x1]=1;//出发点位置在v地图是记录值为1,已经走过
bfs(x1,y1);
if(s) cout<<minn<<endl;//用s做标记判断是否找到解药,一开始标记为0,若找到解药更改为1
else cout<<"-1"<<endl;//找不到解药,输出-1
memset(v,0,sizeof(v));//将mm和v二维数组全部恢复默认值0
memset(mm,0,sizeof(mm));
cin>>m>>n;s=0;minn=9999;//准备测试下一组数据,将这些变化恢复为初始值
}
}