Emmmm ,本着不再发明轮子的原则,网上BFS教程一搜一大堆,所以原理就不再讲了,给出几道题加深理解好了>_<
(不喜欢看博客的看书也行)
1,
- 给你一个n*n的0/1矩阵
- 问完全被1包围的0有多少个(包围的定义类似于围棋)
- n <= 1000 ;
(请先自己思考再往下翻)
SOL :
其实思路很简单,只要从边界处的0开始广搜,能搜到的都变为1,最后剩下的零就是被1完全包围的
2,
- 给你一个n*n的0/1矩阵
- 不同位置之间的移动规则是相邻(上下左右)且亦或值为1(就是一个是1一个是0)。
- 给你m个询问,每个询问为一个二元组(x,y),问从点(x,y)最多可以到达几个点(包括自身)。
- n ≤ 1000, m ≤ 100000 ;
(请先自己思考)
SOL :
首先这明显是广搜题,但如果我们每个询问都去广搜一遍的话复杂度最坏是O(n^2*m)的,显然不行对吧。。
其实我们可以预处理联通块,然后把联通块内的坐标的答案值记录为所属联通块大小,然后按询问回答即可
这样的话预处理是O(n^2),询问是O(m),总复杂度就是O(n^2+m)
3,
这道题题目较复杂,我发个网址:https://www.luogu.org/problemnew/show/P1126
SOL:
首先,由于机器人走的格子与障碍物防止格子并不相同,所以我们要把障碍物从原坐标转化为机器人所走格子的坐标
然后我们考虑这道题,因为与方向有关,所以我们在广搜时要多加一个参数——方向,也就是说队列中记录的是一个状态(包括横纵坐标和方向)。
接着层层向外扩展,直到状态横纵坐标与终点横纵坐标相等即可
这道题较为经典,附上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N = 50 + 2 ; const int dx[]={-1,-1,0,0} ; const int dy[]={-1,0,-1,0} ; const int cx[]={0,-1,0,1} ; const int cy[]={-1,0,1,0} ; inline int read() { int k = 0 , f = 1 ; char c = getchar() ; for( ; !isdigit(c) ; c = getchar()) if(c == '-') f = -1 ; for( ; isdigit(c) ; c = getchar()) k = k*10 + c-'0' ; return k*f ; } struct node { int x,y,d ; int ti ; }a,b,c ; queue<node>q ; int n,m ; int sx,sy,ex,ey,sd ; char dd ; bool gg[N][N], hh[N][N] ; bool vis[11000] ; inline int fun(node s) { // 把每种状态转化成一个独一无二的数,记录该状态有没有被访问过 return s.d*2600 + s.x*50 + s.y ; } int main() { n = read() ; m = read() ; int xx, yy ; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { gg[i][j] = read() ; if(gg[i][j]) for(int k=0;k<4;k++) { // 把障碍物影响到的点映射到机器人所走坐标 xx = i + dx[k] ; yy = j + dy[k] ; if(xx < 1 || yy < 1 || xx >= n || yy >= m) continue ; // 因为靠墙的位置走不了,所以机器人所走矩形为(n-1)*(m-1) hh[xx][yy] = 1 ; } } sx = read() ; sy = read() ; ex = read() ; ey = read() ; if(hh[sx][sy] || hh[ex][ey]) { printf("-1") ; return 0 ; } cin>>dd ; switch(dd) { // 0-3分别表示 左,上,右,下 case 'W' : sd = 0 ; break ; case 'N' : sd = 1 ; break ; case 'E' : sd = 2 ; break ; case 'S' : sd = 3 ; break ; } a.x = sx ; a.y = sy ; a.d = sd ; a.ti = 0 ; q.push(a) ; vis[fun(a)] = 1 ; while(!q.empty()) { a = q.front() ; q.pop() ; if(a.x == ex && a.y == ey) { printf("%d",a.ti) ; return 0 ; } a.ti ++ ; a.d = (a.d + 1) % 4 ; if(!vis[fun(a)]){ q.push(a) ; vis[fun(a)] = 1 ; } a.d = (a.d + 2) % 4 ; // 减2加2模4意义下相同,为防止出现负数就写成+2 if(!vis[fun(a)]) { q.push(a) ; vis[fun(a)] = 1 ; } a.d = (a.d + 1) % 4 ; // 回到原来方向 for(int i=1;i<=3;i++) { a.x += cx[a.d] ; a.y += cy[a.d] ; if(a.x < 1 || a.y < 1 || a.x >= n || a.y >= m) break ; if(hh[a.x][a.y]) break ; if(vis[fun(a)]) continue ; q.push(a) ; vis[fun(a)] = 1 ; } } printf("-1") ; return 0 ; }
我的坐标转化方式:
(暂完,以后遇到题可能还会更)