广度优先搜索入门

来源:互联网 发布:linux中ftp配置 编辑:程序博客网 时间:2024/05/29 15:12

简介:

广度优先搜索(Breadth-first-search),又称宽度优先搜索,简称 bfs,是图的搜索算法之一。与深度优先搜索不同的是,广度优先搜索会先搜索到与起始点距离较近的点,而深搜却是沿着一个分支递归到最后。



对上图进行深搜按照节点访问顺序会得到序列:ABEFCDG

对上图进行宽搜按照节点访问顺序会得到序列:ABCDEFG

宽搜可以理解为,从起点开始一层一层地往外扩展,内层一定会在外层前面被访问到。

与深度优先搜索的对比

深度优先搜索用栈(stack)来实现:

  • 把起始节点压入栈中。
  • 每次从栈顶元素,搜索所有在它下一级的元素,把这些元素压入栈中。(若回溯,栈顶也将弹出。)
  • 找到所要找的元素时结束程序。

广度优先搜索使用队列(queue)来实现:

  • 把起始节点放到队列中。
  • 每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。(查看完毕以后,头部元素弹出,即队首指针右移。)
  • 找到所要找的元素时结束程序。

bfs 的一般写法

 void bfs(起始点){     将起始点放入队列中;     while(如果队列不为空){      访问队列中队首元素x;      删除队首元素;     for (x 可以到达的所有点){         if(该点未被访问过且合法){            将该点加入队列末尾;         }      }   }    队列为空,宽搜结束;}

迷宫问题

相信大家都玩过走迷宫。用 2 维数组来表示一个迷宫
  1. S##.
  2. . . . .
  3. ###T

‘S’表示起点,‘T’表示终点,‘#’表示墙壁,‘ . ‘表示平地。你需要从‘S’出发走到‘T’,每次只能上下左右走动,并且不能走出地图,也不能走进墙壁,每个点只能通过一次。现在要求你求出有多少种走的方案。

  现在需要求解最少步数,我们依然可以用深搜来遍历所有可能性,然后从中选取最优的步数。但是宽搜则不需要搜索所有的路径,因为它的层数是由小到大的特点,它的步数一定是最少的,也就是最优解。所以在这一类问题上,宽搜比深搜更有优势。

实现代码

import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;class Node{int x;int y;int step;Node(int x,int y,int step){this.x = x;this.y = y;this.step = step;}}public class Main {static int next[][] = {{1,0},{-1,0},{0,1},{0,-1}}; //4个方向static int n,m;static int box[][] = new int [100+10][100+10];static char map[][] = new char[100+10][100+10];public static void main(String[] args) {Scanner cin = new Scanner(System.in);n = cin.nextInt(); m = cin.nextInt();String s = "";int startx  = 0, starty = 0;for (int i = 0; i < n; i++) {s = cin.next();for (int j = 0; j <m; j++) {map[i][j] = s.charAt(j);if(map[i][j] == 'S'){startx = i; starty =j;}}//初始化}if(bfs(startx,starty)<0){System.out.println(-1);}}static int bfs(int x,int y){Queue<Node> q = new LinkedList<Node>();q.offer(new Node(x, y,0));  //将起点放入队列中box[x][y] = 1;//该点访问过了while(!q.isEmpty()){Node head = q.poll();//取出队头 进行下面操作int next_x = 0; int next_y = 0;for (int i = 0; i <next.length; i++) {next_x = head.x+next[i][0];next_y = head.y+next[i][1];if(next_x<0||next_y<0||next_x>=n||next_y>=m)continue;if(map[next_x][next_y] == 'T'){System.out.println(head.step+1);return 0;}if(box[next_x][next_y] == 0 && map[next_x][next_y] != '#'){box[next_x][next_y] = 1;Node newNode = new Node(next_x, next_y,head.step+1);q.offer(newNode);}}}return -1;}}

一维坐标的移动

在一个长度为 n 的坐标轴上,小明想从 A点 移动到 B 点。他的移动规则如下:

  1. 向前一步,坐标增加 1
  2. 向后一步,坐标减少 1
  3. 跳跃一步,使得坐标乘 2

小明不能移动到坐标小于 0 或大于 n 的位置。小明想知道从 A 点移动到 B 点的最少步数是多少,你能帮他计算出来么?

输入格式

第一行输入三个整数 nAB,分别代表坐标轴长度,起始点坐标,终点坐标。(0A,Bn5000

输出格式

输出一个整数占一行,代表小明要走的最少步数。

样例输入

10 2 7

样例输出

3

实现代码

import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;class Point{int x;int step;Point(int x,int step){this.x = x;this.step = step;}}public class Main {static void bfs(int x){Queue<Point> q = new LinkedList<Point>();q.offer(new Point(x,0));box[x] = 1;while(!q.isEmpty()){Point head = q.poll();for (int i = 1; i <=3; i++) {int next_x = 0;if(i==1){next_x = head.x+1;}else if(i==2){next_x = head.x-1;}else{next_x = head.x*2;}if(next_x<0||next_x>n) continue;if(next_x == B){System.out.println(head.step+1);return;}if(box[next_x] == 0){box[next_x] = 1;Point newpoint = new Point(next_x,head.step+1);q.offer(newpoint);}}}}static int n, A, B;static int box[] = new int [5000+5];public static void main(String[] args) {Scanner cin = new Scanner(System.in);n = cin.nextInt(); A = cin.nextInt(); B = cin.nextInt();bfs(A);}}





原创粉丝点击