题目如下:
解题思路:
关键就是要利用队列的先进先出的特点,达到广度和深度的搜索,用一个4行2列的二维数组来表示移动的上下左右四个不同方向,还需要一个bool类型的二维数组来标记走过的点避免重复。
先要找到S点,将它放入队列并标记,这是起点,出队,然后判断S点的上下左右四个方向坐标是否越界或者走过,如果能走则将它放入队列,并且记录步数(每当从一点向四周移动一点时,这代表走了一步,并且,该点四周的点记录的步数应该相同),继续出队,判断,入队,步数加1(出队的点基础上),循环下去直到搜索到T点坐标。
解题代码:
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
struct walk
{
int x;
int y;
int step;
}; //记录点的坐标和到达该点的步数
int t[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //上下左右四个方向,0列代表行x,1列代表列y,里面的四个坐标可以交换顺序
int areval(char s[100][100],bool flag[100][100],int n,int m,walk S,walk T)
{ //对迷宫进行搜索,找到T点,返回步数
queue<walk> D;
D.push(S); //先将S点入队
flag[S.x][S.y]=false; //标记该点为走过
while(!D.empty()) //队空代表迷宫全部探索完,不能走到T点
{
walk e=D.front(); //取队头元素
D.pop(); //出队
for(int i=0;i<4;i++) //对该点的四个方向探索
{
walk p;
p.x=e.x+t[i][0];
p.y=e.y+t[i][1]; //新的点
p.step=e.step+1; //步数加1
if(p.x>=n||p.x<0||p.y>=m||p.y<0) continue; //判断该点是否越界
if(s[p.x][p.y]=='#'||flag[p.x][p.y]!=true) continue; //判断该点是否能走和走没走过
if(p.x==T.x&&p.y==T.y) return p.step; //判断是否到了T点,若到了,直接返回步数
D.push(p); //将新点入队
flag[p.x][p.y]=false; //标记该点走过
}
}
return -1; //找不到返回-1
}
int main()
{
char s[100][100]; //记录迷宫
int n,m;
while(cin>>n>>m)
{
walk S,T;
bool flag[100][100]; //用来标记是否走过
fill(&flag[0][0],&flag[99][99]+1,true);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>s[i][j];
if(s[i][j]=='S')
{
S.x=i;S.y=j;S.step=0; //记录S点坐标
}
if(s[i][j]=='T')
{
T.x=i;T.y=j; //记录T点坐标
}
}
}
int steps=areval(s,flag,n,m,S,T);
if(steps<0) cout<<"impossible";
else cout<<steps;
cout<<endl;
}
return 0;
}
后语:
今天ACM竞赛做出了4道题,终于比以前只能做签到题好一些了,一直被ACM竞赛题目虐的失去了信心,今天终于能在其中体验AC的成就感了,曾经的状态又回来了一点,似乎又喜欢上了做题目。