广度优先搜索入门

本文介绍了广度优先搜索(BFS)的基本概念,与深度优先搜索(DFS)的区别,并通过迷宫问题和一维坐标移动的例子展示了BFS的应用。BFS使用队列实现,适用于寻找最近解的问题,例如找到图中两点间的最短路径。文章提供了迷宫问题和坐标移动问题的实现代码,帮助读者理解BFS的实际操作。

简介:

广度优先搜索(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);
	}

}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值