1. 程式人生 > 實用技巧 >BFS模板

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)必須在最前面,防止後面訪問mazevis陣列出現越界。

這樣我們的 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