BFS模板
bfs 模板
- bfs
Code
2_bfs.rar:https://www.90pan.com/b2125384
密碼:tjpl
檔名
bfs.cpp
分數
1
初始化程式碼
#include <stdio.h> #include <queue> using namespace std; int n, m; char maze[110][110]; int main() { int sx, sy; scanf("%d %d", &n, &m); for (int i = 0; i < n; ++i) { scanf("%s", maze[i]); for (int j = 0; j < m; ++j) { if (maze[i][j] == 'S') { sx = i, sy = j; } } } return 0; }
第一步
講解
通過本節課,我們來用 bfs 演算法來解決一個實際問題——迷宮問題。
迷宮問題是在一個方格地圖上,求從起點走到終點的最短路。但是迷宮中障礙,有些方格不能走。
我們已經寫好了輸入,並且找到了起點,現在我們先在main
函式上面寫下bfs
函式的框架,傳入起點。
int bfs(int sx, int sy) {
}
提示
int bfs(int sx, int sy) {
}
int main() {
.....
}
程式碼
#include <stdio.h> #include <queue> using namespace std; int n, m; char maze[110][110]; int bfs(int sx, int sy) { } int main() { int sx, sy; scanf("%d %d", &n, &m); for (int i = 0; i < n; ++i) { scanf("%s", maze[i]); for (int j = 0; j < m; ++j) { if (maze[i][j] == 'S') { sx = i, sy = j; } } } return 0; }
第二步
講解
下面我們定義一個結構體 Point 來存狀態資訊。一個狀態包含點的座標 \(x,y\) 和當前已經走的步數 \(step\)。同時我們還需要標記某個點是否走過,那麼需要另外開一個標記陣列 \(vis\)。在bfs
函式之前,maze
定義之後寫下。
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
其中 Point 裡面有一個建構函式,用來快速構造一個 Point 結構體。
提示
...
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
int bfs(int sx, int sy) {
}
...
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
int bfs(int sx, int sy) {
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第三步
講解
我們知道 bfs 需要用一個佇列來維護,下面我們定義一個用來存狀態的佇列,並且將初始狀態壓入佇列,一併標記初始狀態已經訪問。在 bfs 函式裡面寫下。(註釋可以不用寫)
queue<Point> q;
q.push(Point(sx, sy, 0)); // 初始的時候走了 0 步
vis[sx][sy] = 1; // 標記起點已經訪問了
提示
...
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
}
...
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第四步
講解
當佇列沒有空的時候,我們取出隊首元素來擴充套件其他的狀態。在 bfs 函式裡面寫下
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
}
提示
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
}
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
}
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第五步
講解
接下來我們要對四個方向進行搜尋,我們通過定義一個方向向量來控制搜尋方向。常量的定義一般寫在程式碼頭部,在using namespace std;
下面寫下
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
然後在 bfs 函式的q.pop()
下面繼續寫下搜尋四個方向的程式碼
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
}
提示
...
using namespace std;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int n, m;
...
...
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
}
}
}
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
}
}
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第六步
講解
對於搜尋到的點 \((tx, ty)\),我們首先需要判斷這個點是不是在地圖範圍內,在 bfs 函式上方,結構體定義下方新加一個函式
bool in(int x, int y) {
// 判斷點 (x,y) 是否在地圖範圍內
return 0 <= x && x < n && 0 <= y && y < m;
}
提示
...
bool in(int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
}
int bfs(int sx, int sy) {
...
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
bool in(int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
}
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
}
}
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第七步
講解
對於在地圖內不是障礙的點,如果沒有訪問,標記這個點訪問並且壓入佇列。如果搜到了終點,可以直接返回了。繼續寫下
if (in(tx, ty) && maze[tx][ty] != '#' && !vis[tx][ty]) {
if (maze[tx][ty] == 'T') {
return step + 1;
}
q.push(Point(tx, ty, step + 1));
vis[tx][ty] = 1;
}
注意,in(tx, ty)
必須在最前面,防止後面訪問maze
和vis
陣列出現越界。
這樣我們的 bfs 函式就完成了。最後有一個小地方,如果沒有搜尋到終點,我們需要標識沒有可行的路徑。在 bfs 函式最後面寫下return -1
,這樣在沒有搜到終點的情況下就返回了-1
了。
提示
...
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (in(tx, ty) && maze[tx][ty] != '#' && !vis[tx][ty]) {
if (maze[tx][ty] == 'T') {
return step + 1;
}
q.push(Point(tx, ty, step + 1));
vis[tx][ty] = 1;
}
}
}
return -1;
}
...
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
bool in(int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
}
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (in(tx, ty) && maze[tx][ty] != '#' && !vis[tx][ty]) {
if (maze[tx][ty] == 'T') {
return step + 1;
}
q.push(Point(tx, ty, step + 1));
vis[tx][ty] = 1;
}
}
}
return -1;
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
return 0;
}
第七步
講解
最後,我們在main
函式中呼叫bfs
函式就可以啦。
printf("%d\n", bfs(sx, sy));
提示
...
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
printf("%d\n", bfs(sx, sy));
return 0;
}
程式碼
#include <stdio.h>
#include <queue>
using namespace std;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int n, m;
char maze[110][110];
bool vis[110][110];
struct Point {
int x, y, step;
Point(int _x, int _y, int _step):
x(_x), y(_y), step(_step) {}
};
bool in(int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
}
int bfs(int sx, int sy) {
queue<Point> q;
q.push(Point(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
for (int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (in(tx, ty) && maze[tx][ty] != '#' && !vis[tx][ty]) {
if (maze[tx][ty] == 'T') {
return step + 1;
}
q.push(Point(tx, ty, step + 1));
vis[tx][ty] = 1;
}
}
}
return -1;
}
int main() {
int sx, sy;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", maze[i]);
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 'S') {
sx = i, sy = j;
}
}
}
printf("%d\n", bfs(sx, sy));
return 0;
}
完成講解
終於完成了,點選執行,輸入下面的迷宮看看效果吧。
5 4
T...
.##.
##..
...#
##.S