BFS:
宽搜有两大类
共同点都是 一个状态转化为另一个状态
每一个格子就是一个状态,每一次扩展都是走到与其相邻的格子上去(迷宫)
给一个比较小的矩阵(棋盘)如八数码问题,它整个3*3格子是一个状态,每一次枚举它能变成什么状态,如八数码问题,每次会改变两个数的位置,变一次,变成一个新的矩阵,那么就把这个矩阵称为一个状态(整体)
宽搜:每次取出队头元素,然后将该队头元素扩展出的所有元素放到队尾
需要的数组:判重数组:st[] 一般是入队时判重(这样可以保证每一个点入队一次)
宽搜一般模板
queue <- 初始状态入队 //先将某个初始状态入队
while(queue 非空)
{
t <- 队头 //每次取出队头元素放到t中
for(扩展t) //扩展t结点
{
ver <- 新节点
if(! st[ver]) //入队判重
{
ver -> 队尾 //新节点插入队尾
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/fd780d4427899ed6afdd5f25a6936c7e.png)
BFS能找到最少步数,也就是最短路径
因为BFS是按层来遍历的,会先把所有距离为0的点遍历完,然后再遍历所有距离为1的点,按这样的顺序来遍历的,再遍历所有距离为2的点,一层一层往外扩展,因此第一次扩展到终点时,必然是最短距离
题目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
AC代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.file.attribute.AclEntryFlag;
import java.security.AlgorithmConstraints;
import java.sql.Struct;
import java.text.CollationElementIterator;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;
class in
{
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokenizer = new StringTokenizer("");
static String nextLine() throws IOException { return reader.readLine(); }
static String next() throws IOException
{
while (!tokenizer.hasMoreTokens()) tokenizer = new StringTokenizer(reader.readLine());
return tokenizer.nextToken();
}
static int nextInt() throws IOException { return Integer.parseInt(next()); }
static double nextDouble() throws IOException { return Double.parseDouble(next()); }
static long nextLong() throws IOException { return Long.parseLong(next());}
static BigInteger nextBigInteger() throws IOException
{
BigInteger d = new BigInteger(in.nextLine());
return d;
}
}
class PII
{
int x,y;
public PII(int x ,int y)
{
this.x = x;
this.y = y;
}
}
public class Main
{
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int N = 110;
static int n,m;
static int g[][] = new int[N][N], d[][] = new int[N][N];
static void init(int a[][],int k)
{
for(int i = 0 ; i < N ; i ++)
for(int j = 0 ; j < N ; j ++)
d[i][j] = k;
}
public static int bfs()
{
Queue<PII> q = new LinkedList<>();
init(d,-1);
d[0][0] = 0;
q.add(new PII(0,0));
int dx[] = {-1,0,1,0},dy[] = {0,1,0,-1};
while(q.size() > 0)
{
PII t = q.peek();
q.remove();
for(int i = 0 ; i < 4 ; i ++)
{
int x = t.x + dx[i],y = t.y + dy[i];
if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1)
{
d[x][y] = d[t.x][t.y] + 1;
q.add(new PII(x,y));
}
}
}
return d[n - 1][m - 1];
}
public static void main(String[] args) throws IOException
{
n = in.nextInt();
m = in.nextInt();
for(int i = 0 ; i < n ; i ++)
for(int j = 0 ; j < m ; j ++)
g[i][j] = in.nextInt();
out.print(bfs());
out.flush();
}
}
题目2:
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。
今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。
现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个 R× C的字符矩阵来表示。
字符 S 表示阿尔吉侬所在的位置,字符 E 表示奶酪所在的位置,字符 # 表示墙壁,字符 . 表示可以通行。
阿尔吉侬在 1 个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
输入格式
第一行是一个正整数 T,表示一共有 T组数据。
每一组数据的第一行包含了两个用空格分开的正整数 R
和 C,表示地图是一个 R× C的矩阵。
接下来的 R行描述了地图的具体内容,每一行包含了 C个字符。字符含义如题目描述中所述。保证有且仅有一个 S 和 E。
输出格式
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。
若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。
每组数据的输出结果占一行。
数据范围
1< T≤10,
2≤ R, C≤200
AC代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.file.attribute.AclEntryFlag;
import java.security.AlgorithmConstraints;
import java.sql.Struct;
import java.text.CollationElementIterator;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;
class in
{
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokenizer = new StringTokenizer("");
static String nextLine() throws IOException { return reader.readLine(); }
static String next() throws IOException
{
while (!tokenizer.hasMoreTokens()) tokenizer = new StringTokenizer(reader.readLine());
return tokenizer.nextToken();
}
static int nextInt() throws IOException { return Integer.parseInt(next()); }
static double nextDouble() throws IOException { return Double.parseDouble(next()); }
static long nextLong() throws IOException { return Long.parseLong(next());}
static BigInteger nextBigInteger() throws IOException
{
BigInteger d = new BigInteger(in.nextLine());
return d;
}
}
class PII
{
int x,y;
public PII(int x ,int y)
{
this.x = x;
this.y = y;
}
}
public class Main
{
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int N = 210;
static int R,C;
static char g[][] = new char[N][N]; // 存图
static int dis[][] = new int[N][N]; // 作用1:存起点到各个点的距离; 作用2:判重数组
private static int bfs(PII start, PII end) //bfs函数,传入迷宫的起点和终点坐标
{
Queue<PII> queue = new LinkedList<>(); //建立一个队列
for(int i = 0; i < R; i ++ ) Arrays.fill(dis[i], -1); //先把距离都初始化为-1,-1表示不可到达
dis[start.x][start.y] = 0;//表示起点已经走过了,且距离起点为0
queue.offer(start); //将起点先放入队列
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};//四个方向
while(!queue.isEmpty()) //当队列非空
{
PII t = queue.poll(); // 取出对头元素并删除
// 让该点往上下左右四个方向走,扩展该点
for(int i = 0; i < 4; i ++ )
{
int x = t.x + dx[i], y = t.y + dy[i];// 坐标走到相应的四个地方
if(x < 0 || x >= R || y < 0 || y >= C) continue; //出界
if(g[x][y] == '#') continue; //障碍物
if(dis[x][y] != -1) continue; //之前已经遍历过了
dis[x][y] = dis[t.x][t.y] + 1;//如果能走到,则这个点距离起点的距离是上一个点距离起点的距离+1
if(end.x == x && end.y == y) return dis[x][y]; // 走到终点,返回最小距离
queue.add(new PII(x, y)); // 将新状态加入队尾
}
}
return -1; //否则没有找到
}
public static void main(String[] args ) throws IOException
{
int T = in.nextInt();
while(T -- > 0)
{
R = in.nextInt(); //R行
C = in.nextInt(); //每行C个字符
for(int i = 0; i < R; i ++ ) g[i] = in.next().toCharArray(); //每次读一行,并将字符串转换为字符数组
PII start = null, end = null; //定义起点、终点
for(int i = 0; i < R; i ++ )
{
for(int j = 0; j < C; j ++ )
{
if(g[i][j] == 'S') start = new PII(i, j);
else if(g[i][j] == 'E') end = new PII(i, j);
}
}
int distance = bfs(start, end);
if(distance == -1) out.println("oop!");
else out.println(distance);
out.flush();
}
}
}