广度优先搜索BFS(Breadth First Search)按照广度优先的方式进行搜索,可以理解为“尝试所有下一步可能”地穷举所有可行的方案,并不断尝试,直到找到一种情况满足问题问题的要求。
BFS从起点开始,优先搜索离起点最近的点,然后由这个最近的点扩展其他稍近的点,这样一层一层的扩展,就像水波扩散一样。故而可以把BFS当成并行计算的一种模拟。
广度优先搜索可以用队列实现,而且几乎都是用队列实现,所以要学会广度优先搜索,首先必须要学会队列。而在BFS中,可能不止使用基本的队列,优先队列和双端队列也可能被使用并用来优化BFS。在后续BFS优化的学习中,我们会提到这些知识。
与深度优先搜索不同的是,广度优先搜索会先将与起始点距离较近的点搜索完毕,再继续搜索较远的点,而深搜却是沿着一个分支搜到最后。故而当需要选择搜索方式的时候,评估答案可能出现的位置将作为一个可靠的依据。如果答案出现在浅层,那么使用BFS更好;如果答案出现在深层,那么使用DFS更好。
如果将搜索的过程画出来,那么它就像一棵树,每一个结点都有相应的状态,分别代表了一种可能性。之所以叫做广度优先,是因为我们总是将当前层拓展完之后才会进入树的下一层。
BFS需要借助队列来实现:
参数 bfs(变量)
{
起点设置
将起点入队
如果队列不为空:
取出队首:
枚举此时下一步所有的可能性:
得到下一步的状态
如果下一步是合法的/更优的:
将下一步的状态入队
返回答案
}
若当前坐标为 ( x , y ) (x,y) (x,y),则下一步的坐标即为 ( x − 1 , y ) , ( x + 1 , y ) , ( x , y − 1 ) , ( x , y + 1 ) (x-1,y),(x+1,y),(x,y-1),(x,y+1) (x−1,y),(x+1,y),(x,y−1),(x,y+1)。我们需要在限定条件内走到这些位置。
而我们的状态分为两部分构成,结合这两个状态我们就可以唯一标识一种情况:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
struct node
{
ll x,y;
};
ll dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
ll mp[1010][1010];
bool vis[1010][1010];
ll n,m,ans;
void bfs(ll sx,ll sy)
{
queue<node> q;
q.push(node{sx,sy});
vis[sx][sy]=true;
ans++;
while(!q.empty())
{
node now=q.front();
q.pop();
for(ll i=0;i<4;i++)
{
node New;
New.x=now.x+dx[i];
New.y=now.y+dy[i];
if(New.x>=1 && New.x<=n && New.y>=1 && New.y<=m && !vis[New.x][New.y] && mp[New.x][New.y]<=mp[now.x][now.y])
{
vis[New.x][New.y]=true;
ans++;
q.push(New);
}
}
}
}
int main()
{
cin>>n>>m;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=m;j++)
cin>>mp[i][j];
ll sx,sy;
cin>>sx>>sy;
bfs(sx,sy);
cout<<n*m-ans<<endl;
return 0;
}
P1162 填涂颜色
T1770 洪水
P1443 马的遍历
P1649 [USACO07OCT]Obstacle Course S
P4017 最大食物链计数