热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C/C++编程笔记:BFS广度优先搜索基本思想,图算法就是这么简单

广度优先搜索BFS(BreadthFirstSearch)也称为宽度优先搜索,它是一种先生成的结点先扩展的策略。在广度优先搜索算法中&#x

        广度优先搜索BFS(Breadth First Search)也称为宽度优先搜索,它是一种先生成的结点先扩展的策略。

        在广度优先搜索算法中,解答树上结点的扩展是按它们在树中的层次进行的。首先生成第一层结点,同时检查目标结点是否在所生成的结点中,如果不在,则将所有的第一层结点逐一扩展,得到第二层结点,并检查第二层结点是否包含目标结点,……,对层次为n+1的任一结点进行扩展之前,必须先考虑层次完层次为n的结点的每种可能的状态。因此,对于同一层结点来说,求解问题的价值是相同的,可以按任意顺序来扩展它们。通常采用的原则是先生成的结点先扩展。

      为了便于进行搜索,要设置一个表存储所有的结点。由于在广度优先搜索算法中,要满足先生成的结点先扩展的原则,所以存储结点的表一般采用队列这种数据结构。

      在编写程序时,可用数组q模拟队列。front和rear分别表示队头指针和队尾指针,初始时front=rear=0。

      元素x入队操作为  q[rear++]=x;

      元素x出队操作为  x =q[front++];

      广度优先搜索算法的搜索步骤一般是:

      (1)从队列头取出一个结点,检查它按照扩展规则是否能够扩展,如果能则产生一个新结点。

       (2)检查新生成的结点,看它是否已在队列中存在,如果新结点已经在队列中出现过,就放弃这个结点,然后回到第(1)步。否则,如果新结点未曾在队列中出现过,则将它加入到队列尾。

      (3)检查新结点是否目标结点。如果新结点是目标结点,则搜索成功,程序结束;若新结点不是目标结点,则回到第(1)步,再从队列头取出结点进行扩展。

      最终可能产生两种结果:找到目标结点,或扩展完所有结点而没有找到目标结点。

      如果目标结点存在于解答树的有限层上,广度优先搜索算法一定能保证找到一条通向它的最佳路径,因此广度优先搜索算法特别适用于只需求出最优解的问题。当问题需要给出解的路径,则要保存每个结点的来源,也就是它是从哪一个节点扩展来的。

      对于广度优先搜索算法来说,问题不同则状态结点的结构和结点扩展规则是不同的,但搜索的策略是相同的。广度优先搜索算法的框架一般如下:

void  BFS()

{

    队列初始化;

    初始结点入队;

    while (队列非空)

    {  

          队头元素出队,赋给current;

          while  (current 还可以扩展)

          {

              由结点current扩展出新结点new;

              if  (new 重复于已有的结点状态) continue;

              new结点入队;

              if  (new结点是目标状态)

              {

                    置flag= true;    break; 

               }

          }

      }

}

       对于不同的问题,用广度优先搜索法的算法基本上都是一样的。但表示问题状态的结点数据结构、新结点是否为目标结点和是否为重复结点的判断等方面则有所不同。对具体的问题需要进行具体分析,这些函数要根据具体问题进行编写。

【例1】黑色方块

有一个宽为W、高为H的矩形平面,用黑色和红色两种颜色的方砖铺满。一个小朋友站在一块黑色方块上开始移动,规定移动方向有上、下、左、右四种,且只能在黑色方块上移动(即不能移到红色方块上)。编写一个程序,计算小朋友从起点出发可到达的所有黑色方砖的块数(包括起点)。

      例如,如图1所示的矩形平面中,“#”表示红色砖块,“.”表示黑色砖块,“@”表示小朋友的起点,则小朋友能走到的黑色方砖有28块。

(1)编程思路

      采用广度优先搜索法解决这个问题。

      用数组q模拟队列操作,front为队头指针,rear为队尾指针,初始时front=rear=0。

      入队操作为 q[rear++]=cur;

      出队操作为 cur=q[front++]。

      程序中定义方砖的位置坐标(x,y)为Node类型,定义数组int

visit[N][N]标记某方砖是否已走过,visit[i][j]=0表示坐标(i,j)处的方砖未走过,visit[i][j]=1表示坐标(i,j)处的方砖已走过。初始时visit数组的所有元素值均为0。

      具体算法步骤为:

      ① 将出发点(startx,starty)入队列q,且置visit[startx][starty]=1,表示该处的方砖已被处理,以后不再重复搜索。

      ② 将队列q的队头元素出栈,得到一个当前方砖cur,黑色方砖计数(sum++),沿其上、下、左、右四个方向上搜索未走过的黑色方砖,将找到的黑色方砖的坐标入队列q。

      ③ 重复执行②,直至队列q为空,则求出了所有能走过的黑色方砖数。

(2)源程序

#include

using namespace std;

#define N 21

struct Node

{

       int x;

       int y;

};

int dx[4]={-1,1,0,0};

int dy[4]={0,0,-1,1};

char map[N][N];

int visit[N][N];

int bfs(int startx, int starty,int w,int h)

{

       Node q[N*N],cur,next;   // q为队列

       int  front,rear;        // front为队头指针,rear为队尾指针

       int i,x,y,sum;    

       front=rear=0;           // 队列q初始化

       sum=0;

       cur.x=startx;   cur.y=starty; 

       visit[startx][starty]=1;

       q[rear++]=cur;          // 初始结点入队

       while(rear!=front)      // 队列不为空

       {

              cur=q[front++];     // 队头元素出队

              sum++;              // 方砖计数

              for (i&#61;0;i<4;i&#43;&#43;)

              {

                  x&#61;cur.x&#43;dx[i];  y&#61;cur.y&#43;dy[i];

                 if(x >&#61;0 &&

x&#61;0 && y

&& visit[x][y]&#61;&#61;0)

                 {

                        visit[x][y] &#61; 1;

                        next.x&#61;x;  next.y&#61;y;  // 由cur扩展出新结点next

                        q[rear&#43;&#43;]&#61;next;       // next结点入队

                  } 

              }

       }

       return sum;

}

int main()

{

   int i,j,pos_x,pos_y,w,h,sum;

   while(1)

   {

       cin>>w>>h;

        if (w&#61;&#61;0 && h&#61;&#61;0) break;

       for(i&#61;0;i

       {

          for(j&#61;0;j

          {

              cin>>map[i][j];

              if (map[i][j]&#61;&#61;&#39;&#64;&#39;)

             {

                pos_x &#61; i;

                pos_y &#61; j;

             }

              visit[i][j] &#61; 0;

         }

      }

      sum&#61;bfs(pos_x, pos_y,w,h);

      cout<

   }

   return 0;

}

希望对大家有帮助~

学习C/C&#43;&#43;编程知识&#xff0c;想要成为一个更加优秀的程序员&#xff0c;或者你学习C/C&#43;&#43;&#xff08;数据结构&#xff09;的时候有难度&#xff0c;可以关注咨询笔者&#xff0c;一些学习视频教程以及学习文件都会分享&#xff0c;而且和别人一起交流成长会比自己琢磨更快哦&#xff01;


推荐阅读
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了一个程序,可以输出1000内能被3整除且个位数为6的所有整数。程序使用了循环和条件判断语句来筛选符合条件的整数,并将其输出。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文为Codeforces 1294A题目的解析,主要讨论了Collecting Coins整除+不整除问题。文章详细介绍了题目的背景和要求,并给出了解题思路和代码实现。同时提供了在线测评地址和相关参考链接。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
author-avatar
香水百合-2012
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有