BFS使用队列辅助求解
在使用bfs求解问题前,我们应该至少考虑三个问题:
- 将每个结点作为一种状态,用什么数据结构来记录这种状态
- 用该状态该怎么扩展节点,该节点可以怎样被扩展,要注意边界控制
- 在队列中以什么标准优先扩展,必要时使用优先队列
这三个问题使用下面这个基本迷宫问题回答:
- Node n(x, y);
- 迷宫问题 可以上 下 左 右 四个方向移动。
- 距离短优先,当然会有权值小优先等等。
还有一个问题,我在一道题中遇到的:下面bfs中的vis[u.x][u.y] = 1到底放在哪?
void bfs(int m, int n) {
queue<Node> que;
que.push(Node(0, 0));
while(!que.empty()) {
Node u = que.front(); que.pop();
if(u.x==m-1 && u.y==n-1) return;
for(int i = 0; i < 4; i++) {
int x_t = u.x + dir_x[i];
int y_t = u.y + dir_y[i];
if(matrix[x_t][y_t] && !vis[x_t][y_t] && (x_t>=0 && y_t>=0 && x_t<m && y_t<n)){
// 父结点x,y坐标合并成一个数
fath[x_t][y_t] = u.x*100+u.y;
dis[x_t][y_t] = dis[u.x][u.y] + 1;
vis[u.x][u.y] = 1;
que.push(Node(x_t, y_t));
}
}
}
}
我之前都是习惯放在判定中的,即 判定允许移动到该节点后,便把该节点标记为有1,暗指其他节点遍历不到该点了。(尽管该点还没有遍历到)。
但前几天遇到了一道题便错了,这道题的内容要求 判定过允许到一个节点,但是不能标记该点,因为其他节点遍历时再遍历该点可能会有更优解。题目链接:https://vjudge.net/problem/UVA-1600
然后便发现,(对于普遍的bfs题目)使用前者效率更高,后者会重复遍历节点,看情况使用。有的题卡时间紧,后者就超时了(前几天便遇见了)。
最短距离使用dis二维数组,路径使用fath二维数组,还用使用vis进行是否访问判断。
输入
4 6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
输出
长为:8
0 0
1 0
2 0
3 0
3 1
3 2
3 3
3 4
3 5
#include <iostream>
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
using namespace std;
const int maxn = 20;
int matrix[maxn][maxn], vis[maxn][maxn];
// 距离 和 父结点
int dis[maxn][maxn], fath[maxn][maxn];
int dir_x[4] = {0, 0, -1, 1};
int dir_y[4] = {1, -1, 0, 0};
struct Node {
int x, y;
Node(int _x, int _y):
x(_x), y(_y) {}
};
void bfs(int m, int n) {
queue<Node> que;
que.push(Node(0, 0));
while(!que.empty()) {
Node u = que.front(); que.pop();
if(u.x==m-1 && u.y==n-1) return;
for(int i = 0; i < 4; i++) {
int x_t = u.x + dir_x[i];
int y_t = u.y + dir_y[i];
if(matrix[x_t][y_t] && !vis[x_t][y_t] && (x_t>=0 && y_t>=0 && x_t<m && y_t<n)) {
// 父结点x,y坐标合并成一个数
fath[x_t][y_t] = u.x*100+u.y;
dis[x_t][y_t] = dis[u.x][u.y] + 1;
vis[u.x][u.y] = 1;
que.push(Node(x_t, y_t));
}
}
}
}
int main() {
freopen("i.txt", "r", stdin);
// freopen("o.txt", "w", stdout);
int m, n;
cin >> m >> n;
memset(matrix, 0, sizeof(matrix));
memset(vis, 0, sizeof(matrix));
memset(dis, 0, sizeof(dis));
memset(fath, 0, sizeof(fath));
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
cin >> matrix[i][j];
}
}
bfs(m, n);
cout << "长为:" << dis[m-1][n-1] << endl;
// 将路径存入栈
stack<Node> res;
int x = m-1, y = n-1;
while(true) {
res.push(Node(x, y));
if(!x && !y) break;
int num = fath[x][y];
// 父结点分离
x = num/100;
y = num%100;
}
while(!res.empty()) {
Node u = res.top();
res.pop();
cout << u.x << " " << u.y << endl;
}
return 0;
}