介绍
本篇文章主要介绍三种bfs题型
林大OJ 275:搜索字符串
关注flag初始化的位置,每次在外层循环搜索时都要初始化flag为false,如果把flag改为int型应该会更好些。
稍微改进一点:flag的赋值和使用绑定在同一个if块内,每次进入if块,都会先给flag赋初始值0,无残留污染。

我第一次的代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char a[1005],b[1005];
int cnt;
bool flag;
while(cin>>a>>b)
{
cnt = 0;
for(int i = 0; i<=strlen(a)-strlen(b); i++)
{
flag = false;
if(a[i]==b[0])
{
flag = true;
for(int j = 1; j<strlen(b); j++)
{
if(a[i+j] != b[j])
{
flag = false;
break;
}
}
}
if(flag)
cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
我的第二版代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char a[1005],b[1005];
int cnt,flag;
while(cin>>a>>b)
{
cnt = 0;
for(int i = 0; i<=strlen(a)-strlen(b); i++)
{
if(a[i]==b[0])
{
flag = 0;
for(int j = 1; j<strlen(b); j++)
if(a[i+j] != b[j])
{flag = 1; break;}
if(flag==0) cnt++;
}
}
cout<<cnt<<endl;
}
return 0;
}
林大OJ 558:迷宫寻路-搜索
原始写法:发现合法节点,直接入队(此时节点还是*,未标记)运行600多ms!
这种方式的问题:同一个节点会被多次加入队列,队列中存在大量重复节点。
if(合法 && a[new_x][new_y]=='*') {
q.push({new_x, new_y}); // 入队时不标记,还是*
}
Point temp = q.front();
q.pop();
a[temp.x][temp.y] = '#';
改进:发现合法节点,先标记为#,再入队,当后续其他节点遍历到这个点,发现是#,直接跳过,不会入队,大大节省内存开销
// 发现合法节点,先标记为#,再入队
if(合法 && a[new_x][new_y]=='*') {
a[new_x][new_y] = '#';
q.push({new_x, new_y}); // 入队后,其他节点无法再找到这个*
}
//后续其他节点遍历到这个(new_x, new_y),发现是#,直接跳过,不会入队


#include <bits/stdc++.h>
using namespace std;
struct Point
{
int x,y;
};
char a[1005][1005];
int n,m,begin_x,begin_y,end_x,end_y,new_x,new_y;
int dirs[4][2]={{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
queue<Point> q;
void seek_begin()
{
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(a[i][j]=='*' && (i==0||i==n-1||j==0||j==m-1)){begin_x = i; begin_y = j; return;}
}
void seek_end()
{
for(int i = n-1; i >= 0; i–)
for(int j = m-1; j >= 0; j–)
if(a[i][j]=='*' && (i==0||i==n-1||j==0||j==m-1)){end_x = i; end_y = j; return;}
}
void bfs();
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m){
for(int i = 0; i < n; i++)
cin>>a[i];
bfs();
}
return 0;
}
void bfs()
{
while(!q.empty())
{
q.pop();
}
seek_begin();
seek_end();
q.push({begin_x,begin_y});
a[begin_x][begin_y]='#';
while( !q.empty())
{
Point temp = q.front();
q.pop();
if(temp.x == end_x && temp.y == end_y)
{
cout<<"YES"<<endl;
return ;
}
for(int i = 0; i < 4; i++)
{
new_x=temp.x+dirs[i][0];
new_y=temp.y+dirs[i][1];
if(new_x>=0 && new_x<n && new_y>=0 && new_y<m && a[new_x][new_y]=='*')
{
a[new_x][new_y]='#';
q.push({new_x, new_y});
}
}
}
cout<<"NO"<<endl;
}
林大OJ 784:白与黑-搜索
这道题感觉和迷宫那道题差不多,只不过需要遍历每一个节点。要看清楚题目H和W表示的含义


#include <bits/stdc++.h>
using namespace std;
int W, H, begin_x, begin_y, cnt, new_x, new_y;
char a[25][25];
int dirc[4][2]={{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
struct Point{
int x,y;
};
queue<Point> q;
void seek_start()
{
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++)
if(a[i][j] == '@')
{
begin_x = i;
begin_y = j;
a[i][j] = '.';
return;
}
}
void bfs();
int main()
{
ios::sync_with_stdio(false);
while(cin>>W>>H && (W && H)){
for(int i=0; i < H; i++)
cin>>a[i];
bfs();
}
return 0;
}
void bfs()
{
while(!q.empty())
{
q.pop();
}
cnt = 0;
seek_start();
q.push({begin_x, begin_y});
a[begin_x][begin_y]='#';
cnt++;
while( !q.empty())
{
Point tmp = q.front();
q.pop();
for(int i=0; i < 4;i++)
{
new_x = tmp.x + dirc[i][0];
new_y = tmp.y + dirc[i][1];
if(new_x>=0 && new_x<H && new_y>=0 &&
new_y<W && a[new_x][new_y]=='.')
{
a[new_x][new_y] = '#';
q.push({new_x, new_y});
cnt++;
}
}
}
cout<<cnt<<endl;
}
林大OJ 912:搜索入门-搜索
熟能生巧,和上面两道题差不太多!

#include<bits/stdc++.h>
using namespace std;
int dirc[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int n, new_x, new_y;
char a[5][5];
struct Point{
int x,y;
};
queue<Point> q;
void bfs();
int main()
{
ios::sync_with_stdio(false);
cin>>n;
while(n–)
{
for(int i = 0; i < 4; i++)
cin>>a[i];
bfs();
}
return 0;
}
void bfs()
{
q.push({0, 0});
a[0][0] = '*';
while(!q.empty())
{
Point tmp = q.front();
q.pop();
if(tmp.x == 3 && tmp.y == 3)
{
cout<<"YES"<<endl;
return ;
}
for(int i=0; i < 4; i++)
{
new_x = tmp.x + dirc[i][0];
new_y=tmp.y + dirc[i][1];
if(new_x >= 0 && new_x <= 3 && new_y >= 0 &&
new_y <= 3 && a[new_x][new_y]=='#')
{
a[new_x][new_y] = '*';
q.push({new_x, new_y});
}
}
}
cout<<"NO"<<endl;
}
林大OJ 1214:逃出迷宫-搜索
这道题由于火堆个数是不确定的,所以这种写法被pass掉了
void find_fire()
{
for(int i = 0; i < R; i++)
for(int j = 0; j < C; j++)
if(a[i][j] == 'F')
{
a[i][j]='#';
fire_x = i;
fire_y = j;
return ;
}
}
我看了一些算法的书,发现火堆应该用多源bfs,我们先定义一个数组fire_time来存储每个点啥时候烧着,刚开始把每个点都设成无穷大,表示这个位置不会被火烧到,接着将小明入队,逐层移动,每一步都判断小明下一步到达目标位置的时间 < 该位置被点燃的时间(fire_time数组)。若小明 BFS 过程中找到逃出路径,输出最短时间;若队列空仍未逃出,输出IMPOSSIBLE。


#include<bits/stdc++.h>
using namespace std;
int dirc[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
const int INF = 0x3f3f3f3f; // 无穷大,标记未被点燃/未到达
int T, R, C;
char a[1005][1005];
int fire_time[1005][1005];// 记录每个位置被火堆点燃的时间
int man_time[1005][1005]; // 记录小明到达每个位置的时间
struct Point{
int x, y;
};
queue<Point> q;
void fire_bfs() {
memset(fire_time, INF, sizeof(fire_time));
while (!q.empty()) q.pop();
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
if (a[i][j] == 'F') {
q.push({i, j});
fire_time[i][j] = 0;
}
}
}
// 火堆蔓延BFS
while (!q.empty()) {
Point tmp = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int new_x = tmp.x + dirc[i][0];
int new_y = tmp.y + dirc[i][1];
// 条件:不越界、不是墙、未被点燃
if (new_x >= 0 && new_x < R && new_y >= 0 && new_y < C
&& a[new_x][new_y] != '#' && fire_time[new_x][new_y] == INF)
{
fire_time[new_x][new_y] = fire_time[tmp.x][tmp.y] + 1;//记录这个点什么时候被点燃
q.push({new_x, new_y});
}
}
}
}
// 小明BFS
int man_bfs(int start_x, int start_y) {
memset(man_time, INF, sizeof(man_time));
while (!q.empty()) q.pop();
q.push({start_x, start_y});
man_time[start_x][start_y] = 0;
while (!q.empty()) {
Point tmp = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int new_x = tmp.x + dirc[i][0];
int new_y = tmp.y + dirc[i][1];
// 越界就返回当前时间+1
if (new_x < 0 || new_x >= R || new_y < 0 || new_y >= C) {
return man_time[tmp.x][tmp.y] + 1;
}
if (a[new_x][new_y] != '#' && man_time[new_x][new_y] == INF //现在这个位置没被点着
&& man_time[tmp.x][tmp.y] + 1 < fire_time[new_x][new_y]) //小明下一步走到这个位置的时间,要比火堆烧到这个位置的时间早
{
man_time[new_x][new_y] = man_time[tmp.x][tmp.y] + 1;
q.push({new_x, new_y});
}
}
}
return INF;
}
int main() {
ios::sync_with_stdio(false);
cin >> T;
while (T–) {
cin >> R >> C;
int start_x, start_y;
for (int i = 0; i < R; i++) {
cin >> a[i];
for (int j = 0; j < C; j++) {
if (a[i][j] == 'J') {
start_x = i;
start_y = j;
}
}
}
fire_bfs();
int ans = man_bfs(start_x, start_y);
if (ans == INF) {
cout << "IMPOSSIBLE" << endl;
} else {
cout << ans << endl;
}
}
return 0;
}
林大OJ 1693:瓷砖-搜索


#include <bits/stdc++.h>
using namespace std;
int W, H, begin_x, begin_y, cnt, new_x, new_y;
char a[55][55];
int dirc[4][2]={{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
struct Point{
int x,y;
};
queue<Point> q;
void seek_start()
{
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++)
if(a[i][j] == '@')
{
begin_x = i;
begin_y = j;
a[i][j] = '.';
return;
}
}
void bfs();
int main()
{
ios::sync_with_stdio(false);
while(cin>>W>>H && (W && H)){
for(int i=0; i < H; i++)
cin>>a[i];
bfs();
}
return 0;
}
void bfs()
{
while(!q.empty())
{
q.pop();
}
cnt = 0;
seek_start();
q.push({begin_x, begin_y});
a[begin_x][begin_y]='#';
cnt++;
while( !q.empty())
{
Point tmp = q.front();
q.pop();
for(int i=0; i < 4;i++)
{
new_x = tmp.x + dirc[i][0];
new_y = tmp.y + dirc[i][1];
if(new_x>=0 && new_x<H && new_y>=0 &&
new_y<W && a[new_x][new_y]=='.')
{
a[new_x][new_y] = '#';
q.push({new_x, new_y});
cnt++;
}
}
}
cout<<cnt<<endl;
}





