简介
广度优先搜索算法(BFS),当碰到岔道口时,总是先依次访问从该岔道口能直接到达的所有结点,然后再按这些结点被访问的顺序去依次访问它们能直接到达的所有结点,直到所有结点都被访问为止,类似于树的层次遍历,需要用到队列数据结构。
(1)先访问完当前顶点的所有邻接点。
(2)先访问的顶点的邻接点先于后访问顶点的邻接点被访问。
搜索过程
![](https://i-blog.csdnimg.cn/blog_migrate/5e31b36d238026a4eba3e3e60d8e55d3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f0ecfd210561bcc64f3c05935d5b6805.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e467159695b1d386739edb2d477d334.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e0c9847bab480b2a731556bd9adcfe1d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e9ecb921953a6ce0a9dfa5047e397484.png)
程序模板
void BFS(int s)
{
queue<int> q;
q.push(s);
vis[s]=1;
while(!q.empty()){
int top=q.front();
q.pop();
访问top,if(满足某种条件) return;
将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
}
}
具体应用
- POJ 3278 – Catch That Cow
给定两个整数n和k,通过 n+1或n-1 或n*2 这3种操作,使得n==k,输出最少的操作次数。
利用动态规划(DP)解决问题。
dp[x]表示从N出发到x所需要的最小时间。
dp[x] = N - x,x <= N
dp[x] = dp[x-1] + 1,x > N
dp[x] = min(dp[x], dp[x/2] + 1, dp[x/2+1] + 3),x > N(当x为偶数的时候)
dp[x] = min(dp[x], dp[(x-1)/2] + 2, dp[(x+1)/2] + 2),x>N(当x为奇数的时候)
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int N, K;
const int MAX = 100005;
int dp[MAX];
int main(){
cin >> N >> K;
for(int i = 0; i <= K; ++i){
dp[i] = abs((int)(N - i));
}
for(int i = N+1; i <= K; ++i){
if (i & 1) { // 奇数
dp[i] = min(dp[i], dp[(i-1)/2] + 2);
dp[i] = min(dp[i], dp[i-1] + 1);
dp[i] = min(dp[i], dp[(i+1)/2] + 2);
}else{
dp[i] = min(dp[i], dp[i/2] + 1);
dp[i] = min(dp[i], dp[i-1] + 1);
dp[i] = min(dp[i], dp[i/2 + 1] + 3);
}
}
cout << dp[K] << endl;
return 0;
}
利用广度优先搜索(BFS),已经访问过的数值不再进行下一层的搜索。并进行剪枝,当前要检索的数值为n,其下一层的数值有三个取值n-1,n+1,2*n。设这个取值为temp。当temp<0 或者 temp>maxn 越界,则不管它;temp已经访问过,则不再进行处理。
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 100003;
int change (int x, int ch){//0为x-1,1为x+1,2为2*x
if(ch == 0) return x-1;
else if(ch == 1) return x+1;
else return 2*x;//(ch == 2)
}
struct node{
int num, deep;
node(int _num, int _deep) : num(_num), deep(_deep) {}
};
bool visit[maxn];
int main()
{
int n, k;
while(cin >> n >> k){
memset(visit, false, sizeof(visit));
queue<node> q;
node u(n, 0);
q.push(u);
visit[n] = true;
while (!q.empty()){
u = q.front();
q.pop();
if (u.num == k){
cout << u.deep << endl;
break;
}
for (int i = 0; i < 3; ++i){
int temp = change(u.num, i);
if (temp >= 0 && temp <= maxn && !visit[temp]) {
node v(temp,u.deep+1);
q.push(v);
visit[temp] = true;
}
}
}
}
return 0;
}
5 17
4
- POJ 2251 Dungeon Master
一个立体空间, 输入三个数,L,R,C,代表有L个平面,R行,C列,.代表可以走,#代表不能走,S代表开始点,E代表结束点,问从S开始走,对每个位置,有六个走法,即空间的六个方向的走法(上下东南西北),一分钟可以走一个点,问从S走到E点,最少可以经过多少分钟,若不能到达,则输出Trapped!
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 35;
int L,R,C;
char mmap[maxn][maxn][maxn];
bool vis[maxn][maxn][maxn] = {0};
int dir[6][3] = {{-1,0,0},{1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};//x y z
struct point{
int x, y, z;
int step;
}st,ed;
void bfs(){//cnt统计步数
memset(vis,0,sizeof(vis));
queue<point>q;
point pre,nxt;
vis[st.z][st.x][st.y] = 1;
st.step = 0;
q.push(st);
while(!q.empty()){
pre = q.front();
q.pop();
if(pre.x==ed.x && pre.y==ed.y && pre.z==ed.z){
cout << "Escaped in " << pre.step << " minute(s)." << endl;
return;
}
for(int i=0; i<6; ++i){
int nx = pre.x + dir[i][0];
int ny = pre.y + dir[i][1];
int nz = pre.z + dir[i][2];
if(nx>=0 && nx<R && ny>=0 && ny<C && nz>=0 && nz<L && mmap[nz][nx][ny]!='#' && !vis[nz][nx][ny]){
//也可以写成mmap[nz][nx][ny]=='.'||mmap[nz][nx][ny]=='E' 但不要只写 =='.'
nxt.x = nx; nxt.y = ny; nxt.z = nz;
nxt.step = pre.step+1;
q.push(nxt);
vis[nz][nx][ny] = 1;
}
}
}
cout << "Trapped!" << endl;
}
int main()
{
while(scanf("%d%d%d", &L, &R, &C) && L && R && C){
for(int i = 0; i < L; ++i){
for(int j = 0; j < R; ++j){
scanf("%s", mmap[i][j]);
for(int k = 0; k < C; ++k){
if(mmap[i][j][k] == 'S'){
st.x = j; st.y = k; st.z = i;
}
else if(mmap[i][j][k] == 'E'){
ed.x = j; ed.y = k; ed.z = i;
}
}
}
getchar();
getchar();
}
bfs();
}
}
3 4 5
S....
.###.
.##..
###.#
#####
#####
##.##
##...
#####
#####
#.###
####E
1 3 3
S##
#E#
###
0 0 0
Escaped in 11 minute(s).
Trapped!
三维的空间里,给出起点和终点,“O”表示能走,“X”表示不能走,计算最少的步数。
#include <iostream>
#include <algorithm>
#include <queue>
#define N 106
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int dir[6][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, -1}, {0, -1, 0}, {-1, 0, 0}};
struct node{
int x, y, z, step;
}sa, en;
char g[N][N][N];
int vis[N][N][N], n;
int BFS ()
{
queue <node> que;
vis[sa.x][sa.y][sa.z] = 1;
que.push (sa);
while (!que.empty()){
node top = que.front();
que.pop();
if (top.x==en.x && top.y==en.y && top.z==en.z) return top.step;
for (int i=0; i<6; i++){
node q = top;
q.x += dir[i][0]; q.y += dir[i][1]; q.z += dir[i][2];
if (q.x>=0 && q.x<n && q.y>=0 && q.y<n && q.z>0 && q.z<n && !vis[q.x][q.y][q.z] && g[q.x][q.y][q.z]!='X'){
q.step++;//一层一层从(sa)往外
vis[q.x][q.y][q.z] = 1;
que.push (q);
}
}
}
return -1;
}
int main ()
{
char str1[10], str2[10];//START,END
while (scanf ("%s %d", str1, &n) != EOF){
memset (g, 0, sizeof (g));
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j){
getchar ();
for (int k = 0; k < n; ++k)
scanf ("%c", &g[i][j][k]);
}
}
scanf ("%d%d%d%d%d%d", &sa.z,&sa.y,&sa.x, &en.z,&en.y,&en.x);
sa.step = en.step = 0;
scanf ("%s", str2);
int ans = BFS ();
if (ans != -1) printf ("%d %d\n", n, ans);
else puts ("NO ROUTE");
}
return 0;
}
START 1
O
0 0 0
0 0 0
END
START 3
XXX
XXX
XXX
OOO
OOO
OOO
XXX
XXX
XXX
0 0 1
2 2 1
END
START 5
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
0 0 0
4 4 4
END
1 0
3 4
NO ROUTE