原题链接:点击打开链接
其实现在仔细想想,对初学者而言,在BFS和DFS中,还真是BFS学起来更为容易(至少我是这么认为)。BFS不需要层层递归,不需要考虑搜索路径不符合条件时应该如何变换。它只是一步一步的扫描,然后把相关信息归纳一下而已。我们需要的知识少许的STL知识就行了。
言归正传,这道题应该属于迷宫搜索题,而在搜索过程中,又要找出最少“消耗”的那一条路,从这点看,又有点像图论中的最短路了。因为需要记录消耗,而且需要选择路径,因此,不能用常规BFS中的队列来操作。
因此,建立一个表示坦克状态的结构体,其中包含位置下标i,j,以及从起始位置Y移动到当前位置的消耗cost;
然后,将搜索时的队列改为优先级队列。将消耗更小的设置为高优先级,如:
bool operator < (const place &a,const place &b)
{
return a.cost>b.cost?true:false;
}
这样,每次在队列中的cost表示起点到当前点的消耗,按照消耗小的先出队的次序,当出队的坐标只想目标T时,完成搜索,同时返回“消耗”的值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=302;
char map[maxn][maxn];
bool visit[maxn][maxn];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
struct place
{
int cost,i,j;
};
bool operator < (const place &a,const place &b)//由于在优先队列中,按照cost的大小排序,队头为最优先
{
return a.cost>b.cost?true:false;
}
bool BFS(int si,int sj)
{
place in,out;
priority_queue<place>que;//优先队列que
in.i=si;
in.j=sj;
in.cost=0;
visit[si][sj]=true;//访问起点
que.push(in);//将起点存入队列
while(!que.empty())//队列非空时持续进行
{
out=que.top();//访问队列中最优先点
que.pop();//删除已访问的点
if(map[out.i][out.j]=='T')//如果搜索目的达到,退出函数,返回真值
{
printf("%d\n",out.cost);
return true;
}
for(int i=0;i<4;i++)
{
in.i=out.i+dir[i][0];
in.j=out.j+dir[i][1];
char temp=map[in.i][in.j];
if(in.i<1||in.j<1||temp=='.'||temp=='S'||temp=='R'||visit[in.i][in.j])//设定入队要求
continue;
visit[in.i][in.j]=true;
in.cost=out.cost+1;
if(temp=='B')//如果经B点,cost+1
in.cost++;
que.push(in);//将符合条件的点入队
}
}
return false;
}
int main()
{
int n,m;
while(scanf("%d%d",&m,&n)!=EOF&&(m||n))
{
int si,sj;
memset(map,'.',sizeof(map));
memset(visit,0,sizeof(visit));
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
cin>>map[i][j];
if(map[i][j]=='Y')
{
si=i;
sj=j;
}
}
if(!BFS(si,sj))
printf("-1\n");
}
return 0;
}