广度优先搜索会优先考虑每种状态和初始状态的距离(与初始状态越接近的情况就会越优先考虑),具体一点就是:每个时刻要做的事情就是从上一个时刻每个状态扩展出新的状态。
广度优先搜索使用队列实现:先将初始状态加入到空的队列当中,然后每次取出队首,找出队首所能转移到的状态,再将其插入队列;如此反复,直到队列为空。这样就能保证一个状态在被访问的时候一定是采用最短的路径。
广度优先搜索的一般形式如下:
Q.push(初始状态);//将初始状态入队
while(!Q.empty())
{
State u = Q.front();//取出队首
Q.pop();//队首出队
for(枚举所有可扩展的状态)//找到u的所有可达状态v
{
if(状态合法)//v需要满足某些条件,如未访问过、未在队内等
{
Q.push(v);//入队(同时可能需要维护某些必要信息)
}
}
}
洛谷 P1443 马的遍历
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 410
typedef struct point{ //一个结构体储存x,y两个坐标
int x,y;
}point;
queue<point> Q;//队列
int ans[maxn][maxn];//记录答案,-1代表未访问过
int direction[8][2] = {{2,-1},{2,1},{1,-2},{1,2},
{-1,-2},{-1,2},{-2,-1},{-2,1}};//马能走的八个方向
int main()
{
int n,m,sx,sy;
memset(ans,-1,sizeof(ans));
cin >> n >> m >> sx >> sy;
point tmp;
tmp.x = sx;
tmp.y = sy;
Q.push(tmp);//将起始点入队
ans[sx][sy] = 0;//记录起始点答案
while(!Q.empty())
{
tmp = Q.front();//队首出列
int popx = tmp.x;
int popy = tmp.y;
int d = ans[popx][popy];//取出队首答案
Q.pop();//出队
for(int i = 0 ; i < 8 ; i++)
{
int cx = popx + direction[i][0]; //拓展点的x值
int cy = popy + direction[i][1]; //拓展点的y值
if( cx >= 1 && cx <= n && cy >= 1 && cy <= m && ans[cx][cy] == -1)
{
ans[cx][cy] = d + 1;//记录答案,是上一步多走一步的结果
tmp = {cx,cy};
Q.push(tmp);//满足条件,入队
}
}
}
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= m ; j++)
{
printf("%-5d",ans[i][j]);
}
printf("\n");
}
return 0;
}
洛谷 P1135 奇怪的电梯
#include<iostream>
#include<queue>
using namespace std;
typedef struct node{
int floor;//层数
int time;//按钮次数
}node;
queue<node> Q;//队列
int n,a,b;
int k[1000];//记录每层可以跳跃几层
int vis[1000];//记录是否被访问过
int main()
{
cin >> n >> a >> b;
for( int i = 1 ; i <= n ; i++)
{
cin >> k[i];
}
node tmp = {a,0};
Q.push(tmp);//将起始点插入队列
vis[a] = 1;//记录初始楼层已经被访问过
node now;//最新到达的楼层
while(!Q.empty())
{
now = Q.front();
Q.pop();
if(now.floor == b)
break; //找到目标解
for( int sign = -1 ; sign <= 1 ; sign += 2 )//上下两个方向
{
int curFloor = now.floor + k[now.floor] * sign;//搜索目标的楼层
if( curFloor >= 1 && curFloor <= n && vis[curFloor] == 0)//如果按按钮能够到达该楼层有效且未被访问过
{
tmp = {curFloor,now.time + 1};
Q.push(tmp);//入队
vis[curFloor] = 1; //记录该楼层已被访问过了
}
}
}
if(now.floor == b)
{
cout << now.time << endl;
}
else
{
cout << -1 << endl;
}
return 0;
}