广度优先搜索用队列(边进边出)
1. 日字形走法(象棋)
题目:
Input
There are multiple test cases.
The first line contains an integer T, indicating the number of 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
Just output the minimum steps.
下面以两道题作为例子:
第一道题:
象棋马走日:
马的走向总共有8中可能
#include<iostream>
#include<cstdlib>
#include<stdio.h>
#include<queue>
using namespace std;
// 8中可能的走向
int moveTo[8][2] = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2},
{2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
int chessBoard[8][8];
struct position {
int x;
int y;
int steps;
};
int flag = 1;
bool isValid(int a, int b) {
if (a >= 0&&a < 8&&b >= 0&&b < 8) return true;
else return false;
}
bool isEnd(int a, int b, int c, int d) {
if (a == c && b == d) return true;
else return false;
}
void bfs(int startX, int startY, int endX, int endY) {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
chessBoard[i][j] = 0;
chessBoard[startX][startY] = 1;
flag = 1;
// 用队列实现
queue<position> chessStep;
position p;
p.x = startX;
p.y = startY;
p.steps = 0;
position tem, temp;
chessStep.push(p);
while (!chessStep.empty()) {
tem = chessStep.front();
chessStep.pop();
for (int i = 0; i < 8; i++) {
temp = tem;
temp.x += moveTo[i][0];
temp.y += moveTo[i][1];
if (isValid(temp.x, temp.y)) {
if (chessBoard[temp.x][temp.y] == 0) {
temp.steps++;
if (isEnd(temp.x, temp.y, endX, endY)) {
cout << temp.steps << endl;
flag = 0;
return;
}
// 将当前点能走的方向全部入队
// 通过while循环判断走完第一步后第二步的走向
// 最先到达end的所通过的路径即为最小
chessStep.push(temp);
chessBoard[temp.x][temp.y] = 1;
}
}
}
}
}
int main() {
int n;
char _startx, _endx;
int _starty, _endy;
int startx, endx;
cin >> n;
while (n--) {
cin >> _startx >> _starty >> _endx >> _endy;
_starty -= 1;
_endy -= 1;
startx = _startx - 'a';
endx = _endx - 'a';
bfs(startx, _starty, endx, _endy);
if (flag == 1) cout << "0" << endl;
}
return 0;
}
注: 每次在一个点上,将该点出队,判断其8个方向是否都能够走,如果能够并且为走过,则将该点入队,判断完8个方向后.即通过while进入下一个循环,即第二步
最先到达end的为最短路径,其steps值即为steps最小数目
2.MAZE(迷宫问题)
You are provided a maze(迷宫), and you need to program to find the least steps to walk from the start to the end.And you can only walk in four directions:up, down,left, right.
There will only be 5 kinds of characters in the maze.The meaning of each is as followed.
“#” is for rock, which you can not walk through.
“S” is for start.
“E” is for end.
“.” is for road.
“!” is for magma(岩浆),which you can not walk through.
Input
n,m represent the maze is a nxm maze.(n rows, m columnsm,0
#####
#S..#
#.!.#
#.#E#
#####
#include<iostream>
#include<queue>
using namespace std;
int n, m;
int startX;
int startY;
char maze[30][30];
int moveTo[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// 上下左右四个方向
int flag = 1;
bool isvalidPosition(int n, int m, int indexX, int indexY) {
if (indexX >= 0 && indexX < n && indexY >= 0 && indexY < m)
return true;
else
return false;
}
bool isValidChar(char ch) {
if (ch != '!' && ch != '#') return true;
else return false;
}
struct position {
int x;
int y;
int step;
};
void recursion(int startX, int startY) {
queue<position> mazeQueue;
position p;
p.x = startX;
p.y = startY;
p.step = 0;
mazeQueue.push(p);
position tem, temp;
while (mazeQueue.size()) {
// 越前面元素到达的路径越短,所以到达后直接return
tem = mazeQueue.front();
mazeQueue.pop();
for (int i = 0; i < 4; ++i) {
// 对于当前的位置,判断其上下左右是否可走,若可走则入队
temp = tem;
temp.x += moveTo[i][0];
temp.y += moveTo[i][1];
if (isvalidPosition(n, m, temp.x, temp.y)) {
if (isValidChar(maze[temp.x][temp.y])) {
temp.step++;
if (maze[temp.x][temp.y] == 'E') {
flag = 0;
cout << temp.step << endl;
return;
}
mazeQueue.push(temp);
maze[temp.x][temp.y] = '#';
}
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> maze[i][j];
if (maze[i][j] == 'S') {
startX = i;
startY = j;
}
}
}
recursion(startX, startY);
if (flag)
cout << "-1" << endl;
return 0;
}
这两道题的整体思路几乎一样,记住:广度优先搜索用队列,即一层一层的搜索,相当于是从左到右建立二叉树,以及一层一层的遍历二叉树.