广度优先算法(bfs)
概念:在进行图标搜素的时候,使用队列的原理,获取队列中首个节点,获取首个节点的下挂节点,此时首节点出队列,并标识该节点为已经处理,将查找到的下挂节点入队,返回执行队列首节点出队和下挂节点入队操作,直到满足条件或者队列为空时结束。
举例:有一个全二叉树,每一个节点都有一个value,请获取node1到某个最近节点值是10的路径,全二叉树如下图所示:
如果使用广度优先算法,大概逻辑如下:
1.创建一个队列,并选择一节节点添加到队列(node1:value=5,path=node1)
2.队列不为空,获取队列首个节点(node1)可以到达的节点(node2,node3),并且不是根节点并且value值小于10,因此node1出队列,node2,node3入队列,此时队列中的信息是(node2:value=8,path=node1-node2 node3:value=7,value=node1-node3)
3.队列不为空,获取队列首个节点(node2)可以到达的节点(node4,node5)但是node4和node5是跟节点并且值都不等于10,因此node2出队列,node4,node5丢弃,此时队列中的信息是(node3:value=7,value=node1-node3)
4.队列不为空,获取队列首个节点(node3)可以到达的节点(node6,node7),因为node6已经满足要求则输出结果,使用内存
题:
计算n*m矩阵中两个节点之间的最短路径(包含不可使用节点)
输入:保证m,n是正整数,其余坐标在m,n的范围内
n矩阵长
m矩阵宽
k不可使用节点个数
(x1,y1)...(xk,yk),不可使用的坐标
(xs,ys)(se,ye),开始坐标和技术坐标
输出:
如果可以从开始坐标移动到结束坐标时,输出最短移动步数
如果不能够移动到:输出-1
package com.anran.example.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
public class Main9 {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
// 初始化矩形现状(true表示已经使用或者不可用,false表示未使用)
boolean[][] allInfos = init(sc);
// 获取开始节点信息
int[] startSite = getSiteInfo(sc);
// 获取结束节点信息
int[] endSite = getSiteInfo(sc);
// 使用广度优先算法(bfs)进行搜索
System.out.println(bfs(allInfos, startSite, endSite));
sc.close();
}
private static int bfs(boolean[][] allInfos, int[] startSite, int[] endSite) {
// 创建队列用于存储节点信息
Queue<int[]> queue = new LinkedList<>();
// 将首节点加入到队列中
queue.add(startSite);
allInfos[startSite[0]][startSite[1]] = true;
// 循环处理所有节点
while (!queue.isEmpty()) {
// 获取队列中第一个节点
int[] currentSite = queue.poll();
write("remove", currentSite);
// 判断开始是否是结束
if (checkSite(currentSite, endSite)) return currentSite[2];
// 获取当前节点可以走的节点列表
List<int[]> nextSites = getNextSite(allInfos,currentSite);
write("add", nextSites);
// 将列表中节点加入队列
for (int[] nextSite : nextSites) {
allInfos[nextSite[0]][nextSite[1]] = true;
queue.add(nextSite);
}
}
return -1;
}
private static void write(String str, Object object) {
try {
System.out.println(str + " " + new ObjectMapper().writeValueAsString(object));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
private static List<int[]> getNextSite(boolean[][] allInfos, int[] currentSite) {
List<int[]> nextSites = new ArrayList<>();
int currentX = currentSite[0];
int currentY = currentSite[1];
int nextStep = currentSite[2] + 1;
// 判断左侧是否合适
if (currentY - 1 >=0 && !allInfos[currentX][currentY - 1]) {
int[] site = {currentX, currentY - 1, nextStep};
nextSites.add(site);
}
// 判断上面是否满足要求
if (currentX - 1 >= 0 && !allInfos[currentX - 1][currentY]) {
int[] site = {currentX - 1, currentY, nextStep};
nextSites.add(site);
}
// 判断右侧是否满足要求
if (currentY + 1 < allInfos[0].length && !allInfos[currentX][currentY + 1]) {
int[] site = {currentX, currentY + 1, nextStep};
nextSites.add(site);
}
// 判断下面是否满足要求
if (currentX + 1 < allInfos.length && !allInfos[currentX + 1][currentY]) {
int[] site = {currentX + 1, currentY, nextStep};
nextSites.add(site);
}
return nextSites;
}
private static boolean checkSite(int[] currentSite, int[] endSite) {
if (currentSite[0] != endSite[0] || currentSite[1] != endSite[1]){
return false;
}
return true;
}
private static boolean[][] init(Scanner sc) {
int m = sc.nextInt();
int n = sc.nextInt();
// 初始化矩形信息所有节点为:未执行
boolean[][] allInfos = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j =0; j < n; j++) {
allInfos[i][j] = false;
}
}
// 初始化不能够使用的坐标
int k = sc.nextInt();
for (int i = 0; i < k; i++) {
int[] site = getSiteInfo(sc);
allInfos[site[0]][site[1]] = true;
}
return allInfos;
}
/**
* 获取坐标信息
* @param sc
* @return x坐标 y坐标 距离开始坐标位置
*/
private static int[] getSiteInfo(Scanner sc) {
String[] strs = sc.next().replace("(","").replace(")","").split(",");
int[] ints = new int[3];
ints[0] = Integer.parseInt(strs[0]);
ints[1] = Integer.parseInt(strs[1]);
ints[2] = 0;
return ints;
}
}
输出结果:
5
5
2
(2,1)
(1,2)
(0,0)
(4,3)
remove [0,0,0]
add [[0,1,1],[1,0,1]]
remove [0,1,1]
add [[0,2,2],[1,1,2]]
remove [1,0,1]
add [[2,0,2]]
remove [0,2,2]
add [[0,3,3]]
remove [1,1,2]
add []
remove [2,0,2]
add [[3,0,3]]
remove [0,3,3]
add [[0,4,4],[1,3,4]]
remove [3,0,3]
add [[3,1,4],[4,0,4]]
remove [0,4,4]
add [[1,4,5]]
remove [1,3,4]
add [[2,3,5]]
remove [3,1,4]
add [[3,2,5],[4,1,5]]
remove [4,0,4]
add []
remove [1,4,5]
add [[2,4,6]]
remove [2,3,5]
add [[2,2,6],[3,3,6]]
remove [3,2,5]
add [[4,2,6]]
remove [4,1,5]
add []
remove [2,4,6]
add [[3,4,7]]
remove [2,2,6]
add []
remove [3,3,6]
add [[4,3,7]]
remove [4,2,6]
add []
remove [3,4,7]
add [[4,4,8]]
remove [4,3,7]
7