Acwing走迷宫、八数码 java实现
BFS 宽度优先搜索
1、走迷宫
给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。
数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8
题解
这是一道典型的BFS 当然也可以用动态规划做 用动态规划做简单一些
所有的边权都为1 才可以用BFS 求最短路
其实用数组模拟队列最快了 但是我自己觉得这样写太麻烦 所以就直接导入了util包里面的队列了
java输入输出中的流是很难写的 它就是快 但是写起来麻烦 没有Scanner好写 但是Scanner遇到麻烦的 没有流这种好
但是这道题中由于数据量小 所以数组和队列的写法速度差不多 甚至队列的写法更快
Queue的写法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main{
static int N = 110;
static int[][] d = new int[N][N];
static int[][] map = new int[N][N];
static int n , m ;
public static void main(String[] args)throws Exception{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String[] arr = in.readLine().split(" ");
n = Integer.parseInt(arr[0]);
m = Integer.parseInt(arr[1]);
for(int i = 0 ; i < n ; i++){
String[] cur = in.readLine().split(" ");
for(int j = 0 ; j < m ; j++){
map[i][j] = Integer.parseInt(cur[j]);
d[i][j] = -1 ;//初始化
}
}
System.out.println(bfs());
in.close();
}
static int bfs(){
Queue<Node> q = new LinkedList();//维护队列,用于保存路径
d[0][0] = 0 ;
q.offer(new Node(0,0));
int[] dx = {-1,0,1,0};//上(-1,0) 下(1,0)
int[] dy = {0,1,0,-1};//左(0,-1) 右(0,1)
while(!q.isEmpty()){
Node t = q.poll();
for(int i = 0 ; i < 4 ; i++){
int x = t.x + dx[i]; //这里进行x轴向量判断
int y = t.y + dy[i];//这里进行y轴向量的判断
//然后这里是没走过的距离d是-1;
if(x >= 0 && x < n && y >= 0 && y < m && map[x][y] == 0 && d[x][y] == -1){
//将现在可以走的点(x,y)加上上一个点计数距离的点加上一,就是现在走到的点的距离
d[x][y] = d[t.x][t.y] + 1;
//将新节点添加进队列
q.offer(new Node(x,y));
}
}
}
return d[n-1][m-1]; //最后返回的是地图走到尽头最后一个位置的位置统计的距离
}
public static class Node {
int x ;
int y ;
Node(int x , int y ){
this.x = x ;
this.y = y ;
}
}
}
数组的写法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main{
static int N = 110 , hh , tt;
static int[][] d = new int[N][N];
static int[][] map = new int[N][N];
static Node[] q = new Node[N*N];//用来放每个点的下标
static int n , m ;
public static void main(String[] args)throws Exception{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String[] arr = in.readLine().split(" ");
n = Integer.parseInt(arr[0]);
m = Integer.parseInt(arr[1]);
for(int i = 0 ; i < n ; i++){
String[] cur = in.readLine().split(" ");
for(int j = 0 ; j < m ; j++){
map[i][j] = Integer.parseInt(cur[j]);
d[i][j] = -1 ;//初始化
}
}
System.out.println(bfs());
in.close();
}
static int bfs(){
hh = 0 ; tt = -1 ;
d[0][0] = 0 ;
q[++tt] = new Node(0,0);//插入队列的尾部
//q.offer(new Node(0,0));
int[] dx = {-1,0,1,0};//上(-1,0) 下(1,0)
int[] dy = {0,1,0,-1};//左(0,-1) 右(0,1)
while(hh <= tt){
Node t = q[hh++];//取出头节点
for(int i = 0 ; i < 4 ; i++){
int x = t.x + dx[i]; //这里进行x轴向量判断
int y = t.y + dy[i];//这里进行y轴向量的判断
//然后这里是没走过的距离d是-1;
if(x >= 0 && x < n && y >= 0 && y < m && map[x][y] == 0 && d[x][y] == -1){
//将现在可以走的点(x,y)加上上一个点计数距离的点加上一,就是现在走到的点的距离
d[x][y] = d[t.x][t.y] + 1;
//将新节点添加进队列
q[++tt] = new Node(x,y);
//q.offer(new Node(x,y));
}
}
}
return d[n-1][m-1]; //最后返回的是地图走到尽头最后一个位置的位置统计的距离
}
public static class Node {
int x ;
int y ;
Node(int x , int y ){
this.x = x ;
this.y = y ;
}
}
}
想要输出路径
845.八数码
在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。
例如
1 2 3
x 4 6
7 5 8
题解
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
String state = "" ;
for(int i = 0 ; i < 9 ; i++){
String s = scan.next();
state += s ;
}
System.out.println(bfs(state));
}
public static int bfs(String state){
Queue<String> q = new LinkedList<>();
Map<String,Integer> map = new HashMap<>();
String end = "12345678x";
q.offer(state);
map.put(state,0);
int[] dx = {0, 1, 0, -1};
int[] dy = {1, 0, -1, 0};
while(!q.isEmpty()){
String t = q.poll();
int k = t.indexOf('x');//找到x再String中的下标
int x = k / 3 ; int y = k % 3;//然后进行以为数组转化成二维的操作下标操作
if(t.equals(end)) return map.get(t);
for(int i = 0 ; i < 4 ; i ++ ){//这里进行四种方案
int a = x + dx[i],b = y + dy[i];
if(a >= 0 && a < 3 && b >= 0 && b < 3){ //如果这种情况没有超出边界 移动及距离其实就是交换字符
char[] arr = t.toCharArray();
//然后交换x跟没有超出边界的值进行交换,二维转成一维下标x*3+y;
swap(arr, k, a * 3 + b);
//然后将字符数组转化成字符串
//正常情况下需要恢复状态 但是这里面新开了str就是新的
String str = new String(arr);
if(map.get(str) == null){ //如果这种情况对应的value值是null,说明还没有走过
map.put(str,map.get(t) + 1);//然后将这种情况对应进行上一步的距离加上1
q.offer(str);//然后将新的情况插入到队尾中
}
}
}
}
return -1 ;
}
public static void swap(char[] arr,int x,int y){
char temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)