BFS.1
1.BFS
- 大概分为两种题目:
- 对于地图本身操作(最小步数)或者说二维矩阵上面的距离问题
2.边权唯一和flood fill模型:
3.bfs的特点:
- 求“最小或者求最短”
- 求迭代,“不会爆炸”
4.flood fill
- 在线性时间内,找到某个点的连通块
t1:细胞,最基本的floodfill
代码如下:
-
View Code#include <stdio.h> #include <algorithm> #include <cstring> #define x first #define y second using namespace std; typedef pair<int,int> PII; const int maxn=1010,maxm=1010*1010; char g[maxn][maxn]; bool st[maxn][maxn]; int n,m; PII q[maxm]; inline void bfs(int sx,int sy) { int head=0,tail=0; q[0]={sx,sy}; st[sx][sy]=true; while(head<=tail) { PII t=q[head++]; for(int i=t.x-1;i<=t.x+1;i++) for(int j=t.y-1;j<=t.y+1;j++) { if(i==t.x&&j==t.y) continue; if(i<0||i>=n||j<0||j>=m) continue; if(st[i][j]||g[i][j]=='.') continue; st[i][j]=true; q[++tail]={i,j}; } } } int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",g[i]); int cnt=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(!st[i][j]&&g[i][j]=='W') { bfs(i,j); cnt++; } } printf("%d",cnt); return 0; }
注意编程细节:
- 对于字符串题目,我们可以使用scanf直接读入一行,但同时就需要注意从0开始,判断出边界就是i>=n
- 注意是四联通(有边相连)还是八联通(有点相连)
- 如果是四联通写数组,八联通的话就写pair
- 注意#define x frist 的形式来写
- 对于这样子的话,只能用数组来模拟队列,并且将q定义成相应形式就可
T2城堡
- 四维模型
- 增加返回值就可
- 一般需要注意的(重复遍历,有墙,超出边界)
- 四联通就定义dx,dy数组
T3判断型:
- 增加伴随变量就可
- 注意判断有高有矮一定要注意是在越界之后才判断
- 存在及可能是山峰也可能是山谷的情况
4.单源最短路:
- 在每条边权都相等的情况下,一次bfs求出单元最短路的距离
T1迷宫:
#include <stdio.h> #include <algorithm> #include <cstring> #define x first #define y second using namespace std; typedef pair<int,int> PII; const int maxn=1010,maxm=1010*1010; int g[maxn][maxn]; PII q[maxm]; PII pre[maxn][maxn]; int n,m; void bfs(int sx,int sy) { int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1}; int head=0,tail=0; memset(pre,-1,sizeof(pre)); q[0]={sx,sy}; pre[sx][sy]={0,0};//pre数组也需要初始化 while(head<=tail) { PII t=q[head++]; for(int i=0;i<4;i++) { int a=t.x+dx[i],b=t.y+dy[i]; if(pre[a][b].x!=-1) continue; if(a<0||a>=n||b<0||b>=n) continue; if(g[a][b])continue; q[++tail]={a,b}; pre[a][b]=t; } } } int main() { scanf("%d",&n); for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&g[i][j]); bfs(n-1,n-1); PII end(0,0); while(true) { printf("%d %d\n",end.x,end.y); if(end.x==n-1&&end.y==n-1) break; end=pre[end.x][end.y]; } return 0; }
- 本题经典模型:使用pre数组来存储上一个是从哪一步转移过来的
- 同时,为了节省空间不倒序存储,我们使用反向遍历的技巧【原则:搜索顺序,逆向思维】
- 从n-1,n-1开始搜到0,0;同时用pre转移到上一个去就可;
- 剩下的就没有东西了
- 注意细节和格式
T2
- 类型可以看成对地址的解释方式;
- 在结构体内,所有的数据都会按照结构单元连续的放在一起
- 对齐原理:加入int 4字节,char1字节,最后变成的是八字节
- 本题改变了dx,dy数组,其余不变
- 代码:
-
View Code#include <stdio.h> #include <algorithm> #include <cstring> #define x first #define y second using namespace std; typedef pair<int,int> PII; const int maxn=1010,maxm=1010*1010; int n,m; char g[maxn][maxn]; PII q[maxm]; int dis[maxn][maxn]; inline int bfs() { int dx[]={1,2,2,1,-1,-2,-2,-1}; int dy[]={2,1,-1,-2,-2,-1,1,2}; int sx,sy; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(g[i][j]=='K') { sx=i,sy=j; break; } } int head=0,tail=0; q[0]={sx,sy}; memset(dis,-1,sizeof(dis)); dis[sx][sy]=0; while(head<=tail) { PII t=q[head++]; for(int i=0;i<8;i++) { int a=t.x+dx[i],b=t.y+dy[i]; if(dis[a][b]!=-1) continue; if(a<0||a>=n||b<0||b>=m) continue; if(g[a][b]=='*') continue; if(g[a][b]=='H') return dis[t.x][t.y]+1; dis[a][b]=dis[t.x][t.y]+1; q[++tail]={a,b}; } } } int main() { scanf("%d%d",&m,&n); for(int i=0;i<n;i++) scanf("%s",g[i]); printf("%d",bfs()); return 0; }
T3
- 这题是类比dij
- 这个时候我们发现,这个距离是单调递增的
- 在边权相同的情况下,那么bfs的队列就变成了单调递增
- 最后一题:更变形式,二维专一维,只是更变了写法而已;注意跳的点一定要在范围以内
- 【注意,再这样数轴类型的题目当中,如果没有对于bfs的层数限制,一定要合理的推导出一个上限来限制就可】
浙公网安备 33010602011771号