广度优先搜索_BFS

广度优先搜索算法(英语:Breadth-First Search,缩写为BFS),又译作宽度优先搜索,或横向优先搜索,是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。
BFS是一种盲目搜索法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能地址,彻底地搜索整张图,直到找到结果为止。

实现

  1. 首先将根节点放入队列中。
  2. 从队列中取出第一个节点,并检验它是否为目标。
    * 如果找到目标,则结束搜索并回传结果。
    * 否则将它所有尚未检验过的直接子节点加入队列中。
  3. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜索的目标。结束搜索并回传“找不到目标”。
  4. 重复步骤2。.

动态演示

广度优先搜索_BFS_第1张图片

详细解释

这里以hdu 1312题为例

hdu 1312 "Red and Black"
有一个长方形的房间,铺着方形瓷砖,瓷砖为红色或黑色。一个人站在黑色瓷砖上,他可以按上、下、左、右方向移动到相邻的瓷砖。但他不能在红色瓷砖上移动,只能在黑色瓷砖上移动。编程计算他可以到达的黑色瓷砖的数量。

输入:多组数据,第 1 行包含两个正整数 W 和 H ,W 和 H 分别表示 x 方向和 y 方向上的瓷砖数量。 W 和 H 均不超过 20 ,W 和 H 为 0 时表示输入结束。下面有 H 行,每行包含 W 个字符。每个字符表示一片瓷砖的颜色。用符号表示如下:“ . ” 表示黑色瓷砖;“ # ”表示红色瓷砖;“ @ ” 表示黑色瓷砖上的人,在数据集中只出现一次。

输出:一个数字,这个人从初始瓷砖能到达的瓷砖的总数量(包括起点)

  • 要遍历所有可能的点,可以这样走:从起点1出发,走到它所有的邻居2、3;逐一处理每个邻居,例如在邻居2上,再走它的所有邻居4、5、6,重复上述过程,直到所有点都被走到,如下图所示。这是一个扩散的过程
  • 如果把搜索空间看作一个池塘,丢一颗石头到起点位置,激起的波浪会一层一层地扩散到整个空间。需要注意的是,扩散按从近到远的顺序进行,因此,从每个被扩散的点到起点的路径都是最短的(前提是各边长度相等,若图为加权图,则不一定是最优解)。这个特征对解决迷宫这样的最短路径问题很有用。
  • 用队列来处理这个扩散过程非常清晰、易懂。事实上,甚至可以说 “BFS=队列”
  • c++提供了队列这个数据结构,头文件为 queue , 使用起来非常简单方便。

广度优先搜索_BFS_第2张图片

  • 1 进队。当前队列是 { 1 }

广度优先搜索_BFS_第3张图片

  • 1 出队,1 的邻居 2、3 进队。当前队列为 { 2,3 } (可以理解为从1扩散到2、3)

广度优先搜索_BFS_第4张图片

  • 2出队,2的邻居4、5、6进队。当前队列是 {3,4,5,6} (可以理解为从2扩散到4、5、6)

广度优先搜索_BFS_第5张图片

  • 3出队,7、8进队,当前队列为 {4,5,6,7,8}

广度优先搜索_BFS_第6张图片

  • 4出队,9进队,当前队列为{5,6,7,8,9}

广度优先搜索_BFS_第7张图片

  • 5出队,10进队,当前队列为{6,7,8,9,10}

广度优先搜索_BFS_第8张图片

  • 6出队,11进队,当前队列为{7,8,9,10,11}

广度优先搜索_BFS_第9张图片

  • 7出队,12、13进队,当前队列为{8,9,10,11,12,13}
  • 8出队,无邻居进队,当前队列为{9,10,11,12,13}
  • 9出队,无邻居进队,当前队列为{10,11,12,13}
    广度优先搜索_BFS_第10张图片
  • 10出队,14进队,当前队列为{11,12,13,14}
    广度优先搜索_BFS_第11张图片
  • 11出队,15进队,当前队列为{12,13,14,15}
  • 12出队,无邻居进队,当前队列为{13,14,15}
  • 13出队,无邻居进队,当前队列为{14,15}
  • 14出队,无邻居进队,当前队列为{15}
  • 15出队,无邻居进队,当前队列为{} ,队列为空,程序执行结束,返回结果为15

上述过程说明了整个搜索过程,下面用代码来实现:

#include 
#include 
using namespace std;

char room[23][23];
int dir[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};//四个方向,左上右下
int W,H,ans;

//判断当前坐标是否在房间内
bool check(int x,int y){ return (x>=1 && x<=W && y>=1 && y<=H); }
//存储点的坐标
struct node{ int x,y; };

void BFS(int dx,int dy){
    ans = 1; //起点也包含在瓷砖内
    queue<node> q;
    node start,nexted;
    start.x = dx;
    start.y = dy;
    q.push(start);//第一步的 1 进队
    while(!q.empty()){//若队列q已经为空,说明已经搜索完毕
        start = q.front();
        q.pop();
        for(int i=0;i<4;i++){//遍历当前位置的邻居
            nexted.x = start.x + dir[i][0];
            nexted.y = start.y + dir[i][1];
            if(check(nexted.x,nexted.y) && room[nexted.x][nexted.y]=='.'){
                room[nexted.x][nexted.y] = '#'; //进队后标记为已处理
                ans++;
                q.push(nexted);
            }
        }
    }
}

int main()
{
    int x,y,dx(0),dy(0);
    while(cin>>W>>H){
        if(W==0 && H==0)
            break;
        for(y=1;y<=H;y++){
            for(x=1;x<=W;x++){
                cin>>room[x][y];
                if(room[x][y] == '@'){
                    dx = x;
                    dy = y;
                }
            }
        }
        ans = 0;
        BFS(dx,dy);
        cout<<ans<<endl;
    }

    return 0;
}

参考文献:
算法竞赛-从入门到进阶(罗永军,郭卫斌著)

你可能感兴趣的:(算法竞赛,c++,算法,acm竞赛)