广度优先搜索的用途:广度优先搜索和深度优先搜索所针对的题型很相似,比如迷宫型问题、数字列问题以及状态
搜索等问题。但是它和深度优先搜索的区别在于,深度优先搜索的适用范围更加广泛,因为深度优先搜索存在局限
性,有些题目适用深度优先搜索算法可能会出现“深度无限”的问题,这将导致可怕的无限循环。
但这并不代表深度优先搜索算法比广度差,由于广度优先搜索需要适用队列储存所有点的状态,这样会比深度更加
消耗空间,在题目数据相对较大时,就容易超内存。而所以深度优先搜索更加适用于数据规模较大的情况,当然一切
都还要根据具体的情况而定。
广度优先搜索还有一种叫做状态压缩的问题,由于这个问题也是一种较难理解的思想,我会单独用一篇博客进行讲解,
请另见博客。
广度优先搜索的思路:了解过深度优先搜索的人应该知道,深度优先搜索的实现一般为栈、递归或者优先队列,而
广度优先搜索的实现常常用普通的队列,而且其思想较易于理解。
它的实际思想就是从起点出发,把起点周围方向上的点存入队列,在从队列头取出一个点,再将该店方向上的点存入
队列,重复存取操作,直到遇见符合条件的点则退出函数,或者一直没有符合条件的点,则直至队列为空,退出函数。
同深度优先搜索相同,你必须首先确定方向问题,比如在迷宫问题中,你需要用一个二维的4*2或者8*2数组表示四个
或八个方向,还需要使用数组或者其他什么方式标志已经遍历过的点。
例题解析:接下来我将用一道较简单的题进行讲解,加强理解
A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.
Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
Input
The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
Output
For each test case, print one line saying "To get from xx to yy takes n knight moves.".
Sample Input
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
Sample Output
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.
题目大意:给定一个8*8数组,行数用“a-h”表示,列数用“1-8”表示,然后给出一个起点和终点要求计算出从
起点到终点的最短步数。需要注意的是,移动的方式是类型象棋中的马,按照“日”字移动,比如
1 0
0 0
0 1
1移动到1的这种方式
代码:
#include
#include
#include
#include
using namespace std;
int row_x1, row_x2;//记录起点和终点的行数,数字表示
int col_y1, col_y2;//记录起点和终点的列数,数字表示
char char_x1, char_x2;//记录起点和终点的行数,字母表示
int step; //记录步数
bool mark[10][10]; //用于记录点是否被遍历过
int dir[8][2] = { {-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2} };//方向
struct Node{
int x, y, step;
};
queue Q;
void BFS()
{
Node now, next;
while (!Q.empty()) //每次调用函数,都要清空队列
Q.pop();
now.x = row_x1;
now.y = col_y1;
now.step = 0;
Q.push(now); //压入结点
while (!Q.empty()) {
now = Q.front();
Q.pop();
for (int i = 0; i < 8; i++) {
next.x = now.x + dir[i][0];
next.y = now.y + dir[i][1];
if (next.x < 0 || next.x >= 8 || next.y < 0 //判断是否符合要求
|| next.y >= 8 || mark[next.x][next.y])
continue;
mark[next.x][next.y] = true; //标记已经遍历过
next.step = now.step + 1; //在前一步基础之上加一
Q.push(next); //压入队列
if (next.x == row_x2 && next.y == col_y2) { //符合要求则退出函数
cout << "To get from " << char_x1 << col_y1 + 1
<< " to " << char_x2 << col_y2 + 1 << " takes "
<< next.step << " knight moves." << endl;
return;
}
}
}
}
int main(void)
{
ios::sync_with_stdio(false);
while (cin >> char_x1 >> col_y1 >> char_x2 >> col_y2) {
row_x1 = char_x1 - 'a'; col_y1 -= 1; //将字母表示转换为数字表示
row_x2 = char_x2 - 'a'; col_y2 -= 1;
if (row_x1 == row_x2 && col_y1 == col_y2) {
cout << "To get from " << char_x1 << col_y1 + 1
<< " to " << char_x2 << col_y2 + 1 << " takes 0 knight moves." << endl;
}
else {
//这里值得注意的是,二维数组的重置方式和一维数组的重置方式一样,用memset函数
memset(mark, false, sizeof(mark)); //每次都要重置标记数组
BFS();
}
}
return 0;
}
我相信你收获到的不只是算法,还有思想。