1 BFS模版
按层次的顺序进行遍历
void BFS(int s){
queue<int> q;
q.push(s);
while(){
取出队首元素top;
访问队首元素;
将队首元素出队;
将top的下一层结点未入队的结点全部入队,并设置为已入队;
}
}
2 详细说明
- 1 定义队列q,并将队首s入队
- 2 写一个while循环,循环条件是队列q非空
- 3 在while循环中,先取队首元素top,并访问它(访问:可以是任何事,比如将其输出),将其出队
- 4 将top的下一层结点中所有未曾入队的元素入队,并标记它们的层号为now+1,同时设置这些入队的结点已入队
- 5 返回2继续循环
3 题目
给出一个m*n的矩阵,矩阵中的元素为0或1,称位置(x,y)与其上下左右四个位置(x,y+1),(x,y-1),(x+1,y)(x-1,y)是相邻的。如果矩阵中有若干个1是相邻的(不必两两相邻),那么这些1构成了一个“块“。求给定的矩阵中”块“的个数。
例如下面的6 * 7 矩阵,“块”的个数为4
Sample Input:
6 7
0 1 1 1 0 0 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 1 0
1 1 1 0 1 0 0
1 1 1 1 0 0 0
Sample Output:
4
参考代码:
#include <cstdio>
#include <queue>
using std::queue;
const int MAXN =100;
struct node
{
int x,y;//位置x,y
}Node;
int n, m; //矩阵大小m,n
int matrix[MAXN][MAXN];//矩阵
bool inq[MAXN][MAXN] = {false};//记录{x,y}是否入队
int X[4] = {0, 0, 1, -1};//增量数组
int Y[4] = {1, -1, 0, 0};
bool judge(int x, int y){
//越界
if(x >= n || x < 0 || y >= m || y < 0) return false;
//当前位置为0,或(x,y)已如果队
if(matrix[x][y] == 0 || inq[x][y] == true) return false;
return true;
}
void BFS(int x, int y){
queue<node> Q;//定义队列
Node.x = x;
Node.y = y;
Q.push(Node);//将结点入队
inq[x][y] = true;//设置(x,y)已入队
while(!Q.empty()){
node top = Q.front();//取出队首元素
Q.pop();//队首元素出队
for (int i = 0; i < 4; ++i)//循环四次,得到4个相邻的位置
{
int newX = top.x + X[i];
int newY = top.y + Y[i];
if(judge(newX, newY)){//如果新位置需要访问
//将Node坐标设置为(newX, newY)
Node.x = newX;
Node.y = newY;
Q.push(Node);//将结点Node入队
inq[newX][newY] = true;//设置(newX,newY)已入过队
}
}
}
}
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
for (int x = 0; x < n; ++x)
{
for (int y = 0; y < m; ++y)
{
scanf("%d", &matrix[x][y]);//读入01矩阵
}
}
int ans = 0;//存放块
for (int x = 0; x < n; ++x)//枚举每个位置
{
for (int y = 0; y < m; ++y)
{
//如果元素为1,且未入队
if(matrix[x][y] == 1 && inq[x][y] == false){
ans++;
BFS(x,y);//访问整个块,将该块的所有1的inq都标记为1
}
}
}
printf("%d\n", ans);
return 0;
}
4 题目
给定一个nm大小的迷宫,其中 * 代表不可通过的墙壁,而"."代表平地,S代表起点,T代表终点。移动过程中,如果当前位置是(x,y)(下标从0开始),且每次只能前往上下左右(x,y+1),(x,y-1),(x-1,y)(x+1,y)四个位置的平地,求从起点S达到终点T的最少步数。
…
...
.**.
…T.
上面样例中,S的坐标我饿(2,2),T的坐标为(4,3)
Sample Input:
5 5 //5行5列
..... //迷宫信息
.*.*.
.***.
...T.
2 2 4 3 //起点S的坐标和终点T的坐标
Sample Output:
11
参考代码:
#include <cstdio>
#include <queue>
using std::queue;
const int MAXN = 100;
struct node
{
int x, y;
int step;
}S, Node, T;
int m,n; //m行,n列
char maze[MAXN][MAXN];
bool inq[MAXN][MAXN] = {false};
int X[] = {0, 0, 1, -1};
int Y[] = {1, -1, 0, 0};
bool Test(int x, int y){//判断坐标(x,y)是否有效
if(x < 0 || x >= n || y < 0 || y >= m) return false;
if(inq[x][y] == true || maze[x][y] == '*') return false;//已入过队列,或者墙壁
return true;
}
int BFS(){
queue<node> Q;//1 定义队列
Q.push(S);//2 将起点入队
inq[S.x][S.y] = true;
while(!Q.empty()){
node top = Q.front();//3 取出队首元素
Q.pop(); //4 队首元素出队
if(top.x == T.x && top.y == T.y){
return top.step;//终点,直接返回最少步数
}
for (int i = 0; i < 4; ++i)//将top下一层结点未入队的入队,并标记为已入队
{
int new_x = top.x + X[i];
int new_y = top.y + Y[i];
if(Test(new_x, new_y) == true){
Node.x = new_x;
Node.y = new_y;
Node.step = top.step + 1;//Node层数为top层数加1
Q.push(Node);
inq[new_x][new_y] = true;
}
}
}
return -1;//无法达到终点
}
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
{
getchar();//过滤掉每个换行符
for (int j = 0; j < m; ++j)
{
maze[i][j] = getchar();
}
maze[i][m + 1] = '\0';
}
scanf("%d%d%d%d", &S.x, &S.y, &T.x, &T.y);
S.step = 0;//初始化层数为0,S到T的最小步数为0
printf("%d\n", BFS());
return 0;
}
5 注意点
- BFS中设置的inq为是否结点已经入队,而不是结点是否已被访问,
- 如果设置成是否已被访问,就会造成很多结点重复入队(该结点正在队中,但还没有被访问,其他结点也可以到达该结点,使得该结点再次入队)
- 使用STL中的queue队列,把元素入队,只是把该元素的一个副本入队,入队后
- 队列中元素副本的修改,不会改变原元素
- 对原元素的修改,也不会该拜年队列中元素的副本
- 这样可能会引入bug(一般由结构体造成)
#include <cstdio>
#include <queue>
using std::queue;
struct node
{
int data;
}a[10];
int main(int argc, char const *argv[])
{
queue<node> q;
for (int i = 1; i != 4; ++i)
{
a[i].data = i;
q.push(a[i]);
}
q.front().data = 100;
printf("%d %d %d\n", a[1].data, a[2].data, a[3].data);
a[1].data = 200;
printf("%d\n", q.front().data);
return 0;
}
运行结果:
- 改进办法,当队列中的元素需要修改时,队列中存的元素最好不要时它本身,而是它们的编号(如数组的话,存放其下标)
可以把上面的程序改为:
#include <cstdio>
#include <queue>
using std::queue;
struct node
{
int data;
}a[10];
int main(int argc, char const *argv[])
{
queue<int> q;
for (int i = 1; i != 4; ++i)
{
a[i].data = i;
q.push(i);
}
a[q.front()].data = 100;
printf("%d\n", a[1].data);
return 0;
}