一提到BFS的时候大家一般都会申请一个数组vis,vis的作用是用来标记有没有搜索过,如果搜索过那么vis = 1,如果没有搜索过那么vis = 0,在每一次搜索的时候都会重新初始化vis, 把vis初始化为0,如果查询的次数比较多,那么就白白浪费了很多时间,很多的操作其实都是重复的,所以这篇博客讲述BFS+记忆搜索。
大家在做BFS题的时候有没有意识到其实BFS在搜索的时候只是搜索连通的某块,就比如说你在一个荒岛上,其他人在另外一个岛上,你和其他人也没有办法取得联系,所以BFS的搜索也是一个道题,BFS模块搜索的其实只是互相连通模块,如果不互相连通那么这些模块其实没有任何关系,也就是不能相互到达。所以在记忆化搜索时vis就不用每次初始化,一次就行,vis用来记录可以相互到达的模块。在每次查询的时候只要先询问是否被分配到一个模块中,如果没有在就用BFS查询,如果有直接就知道这个模块的中几个点可以相互到达。
01迷宫 洛谷 P1141
连接:https://www.luogu.org/problemnew/show/P1141
题意:有一个仅由数字00与11组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
题解:题意很简单,但是查询的次数比较多,如果只用最普通的查询那么这道题会直接TLE的,一开始我就直接普通的BFS算法,但是只通过了70%,其中有三个直接TLE,有三个点的数据太大,不适合直接查询,所以需要BFS+记忆化,只要某些点在同一个某块中这些点就可以相互到达。
这个是一开始大代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define N 1005
struct Node{
int x, y;
char pre;
}tmp1, tmp2;
char a[N][N];
int n, step;
int dx[8]={1,-1,0,0};
int dy[8]={0,0,1,-1,};
int vis[N][N];
void bfs(int st, int en){
memset(vis, 0, sizeof(vis));
step = 0;
tmp1.x = st;
tmp1.y = en;
vis[st][en]= 1;
tmp1.pre = a[st][en];
queue<Node>q;
q.push(tmp1);
while(!q.empty()){
tmp1 = q.front();
q.pop();
//cout<<tmp1.x<<" "<<tmp1.y<<endl;
for(int i = 0; i < 8; i++){
tmp2.x = tmp1.x + dx[i];
tmp2.y = tmp1.y + dy[i];
if(tmp2.x >= 0 && tmp2.x<n && tmp2.y>= 0&&tmp2.y < n && !vis[tmp2.x][tmp2.y]&& a[tmp2.x][tmp2.y]!=tmp1.pre){
vis[tmp2.x][tmp2.y] = 1;
tmp2.pre = a[tmp2.x][tmp2.y];
q.push(tmp2);
step++;
}
}
}
}
int main(){
int m, st, en;
cin>>n>>m;
for(int i = 0; i < n; i++){
scanf("%s", a[i]);
}
while(m--){
cin>>st>>en;
bfs(st-1, en-1);
cout<<step+1<<endl;
}
return 0;
}
这个是AC代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define N 1005
#define maxn 1000005
struct Node
{
int x, y;
char pre;
} tmp1, tmp2;
char a[N][N];
int n, num = 0;
int dx[8]= {1,-1,0,0};
int dy[8]= {0,0,1,-1,};
int vis[N][N];
int ans[maxn];
int bfs(int st, int en)
{
num++;
int step = 1;
tmp1.x = st;
tmp1.y = en;
vis[st][en]= num;
tmp1.pre = a[st][en];
queue<Node>q;
q.push(tmp1);
while(!q.empty())
{
tmp1 = q.front();
q.pop();
for(int i = 0; i < 8; i++)
{
tmp2.x = tmp1.x + dx[i];
tmp2.y = tmp1.y + dy[i];
if(tmp2.x >= 0 && tmp2.x<n && tmp2.y>= 0&&tmp2.y < n && !vis[tmp2.x][tmp2.y]&& a[tmp2.x][tmp2.y]!=tmp1.pre)
{
vis[tmp2.x][tmp2.y] = num;
tmp2.pre = a[tmp2.x][tmp2.y];
q.push(tmp2);
step++;
}
}
}
ans[num] = step;
return step;
}
int main()
{
int m, st, en;
cin>>n>>m;
for(int i = 0; i < n; i++)
{
scanf("%s", a[i]);
}
while(m--)
{
cin>>st>>en;
if(!vis[st-1][en-1])//查询是否在一个模块中
cout<<bfs(st-1, en-1)<<endl;
else cout<<ans[vis[st-1][en-1]]<<endl;
}
return 0;
}