BFS:1、“求最小” 用bfs第一次搜到的值就是最小值
2、基迭代,不会爆栈
845. 八数码 - AcWing题库
import java.util.*;
public class Main{
public static void swap(char[] arr, int a, int b){
char temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static int bfs(String start, String end){
Map<String, Integer> map = new HashMap<>();//用来存储到达每种状态要走的距离
Queue<String> q = new LinkedList<>();
q.offer(start);
map.put(start, 0);
int[] dx = {-1,0,1,0}, dy = {0,1,0,-1};//上下左右四个方向
while(!q.isEmpty()){
String t = q.poll();//取出队头元素
int k = t.indexOf('x');//找到元素x在这个字符串里的位置
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 < 3 && a >= 0 && b < 3 && b >= 0){//如果没有超出边界
char[] arr = t.toCharArray();
swap(arr, k, a * 3 + b);//交换位置,二维转化成一维
//将交换位置后的字符数组变成新的字符串
String str = new String(arr);
if(map.get(str) == null){//说明这种状态还没有走到过
map.put(str, map.get(t) + 1);//交换数加1
q.offer(str);//加入队列
}
}
}
}
return -1;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String start = "";
for(int i = 1; i <= 9; i ++){
String s = sc.next();
start += s;
}
String end = "12345678x";
System.out.print(bfs(start, end));
}
}
Flood Fill算法:
可以在线性的时间复杂度内,找到某个点所在的连通块。
1097. 池塘计数 - AcWing题库
import java.util.*;
import java.io.*;
class PII{
int x, y;
public PII(int x, int y){//一个点的横纵坐标
this.x = x;
this.y = y;
}
}
public class Main{
static int N = 1010, M = N * N;
static int n, m;
static PII[] q = new PII[M];
static char[][] g = new char[N][N];
static boolean[][] st = new boolean[N][N];
public static void bfs(int x, int y){
int hh = 0, tt = -1;
q[++ tt] = new PII(x, y);//把这个点加入队列
while(hh <= tt){
PII t = q[hh ++];//取出队头
int a = t.x;//横坐标
int b = t.y;//纵坐标
for(int i = a - 1; i <= a + 1; i ++){
for(int j = b - 1; j <= b + 1; j ++){
if(i == a && j == b) continue;
if(i < 0 || j < 0 || i >= n || j >= m) continue;//如果就是这个点
if(g[i][j] == '.' || st[i][j]) continue;//如果不是水或者是已经遍历过了
q[++ tt] = new PII(i, j);//把这个点加入队列
st[i][j] = true;//标记位遍历过
}
}
}
}
public static void main(String[] args)throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
for(int i = 0; i < n; i ++){
String str = br.readLine();
char[] arr = str.toCharArray();
for(int j = 0; j < m; j ++){
g[i][j] = arr[j];
}
}
int cnt = 0;//记录遍历了多少个连通块
for(int i = 0; i < n; i ++){
for(int j = 0; j < m; j ++){
if(g[i][j] == 'W' && !st[i][j]){//如果是水,而且没有遍历过
bfs(i, j);
cnt ++;
}
}
}
System.out.print(cnt);
}
}
1098. 城堡问题 - AcWing题库
import java.util.*;
class PII{
int x, y;
public PII(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main{
static int N = 60, M = N * N;
static int n, m;
static int[][] g = new int[N][N];
static PII[] q = new PII[M];
static boolean[][] st = new boolean[N][N];
public static int bfs(int x, int y){
int hh = 0, tt = -1;//队头和队尾
int[] dx = {0, -1, 0, 1}, dy = {-1, 0, 1, 0};//西北东南四个方向
q[++ tt] = new PII(x, y);//加入队列
st[x][y] = true;//标记为已经遍历过
int res = 0;//面积
while(hh <= tt){
PII t = q[hh ++];//取出元素
res ++;//取出一个就加上一个
for(int i = 0; i < 4; i ++){
int a = t.x + dx[i];//四个方向
int b = t.y + dy[i];
if(a < 0 || b < 0 || a >= n || b >= m) continue;//越界
if(st[a][b]) continue;//如果已经遍历过
if((g[t.x][t.y] >> i & 1) == 1) continue;//用二进制来表示墙
q[++ tt] = new PII(a, b);//加入队列
st[a][b] = true;//标记为已经遍历过
}
}
return res;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j ++){
g[i][j] = sc.nextInt();
}
}
int cnt = 0;//连通块的数量
int area = 0;//面积
for(int i = 0; i < n; i ++){
for(int j = 0; j < m; j ++){
if(!st[i][j]){
area = Math.max(area, bfs(i, j));
cnt ++;
}
}
}
System.out.println(cnt);
System.out.println(area);
}
}
1106. 山峰和山谷 - AcWing题库
import java.util.*;
class PII{
int x, y;
public PII(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main{
static int N = 1010, M = N * N;
static int n;
static int[][] g = new int[N][N];
static boolean[][] st = new boolean[N][N];
static PII[] q = new PII[M];
static boolean has_higher, has_lower;
public static void bfs(int x, int y){
int hh = 0, tt = -1;
q[++ tt] = new PII(x, y);
st[x][y] = true;//标记为走过
while(hh <= tt){
PII t = q[hh ++];
for(int i = t.x - 1; i <= t.x + 1; i ++){
for(int j = t.y - 1; j <= t.y + 1; j ++){
if(t.x == i && t.y == j) continue;
if(i < 0 || j < 0 || i >= n || j >= n) continue;
if(g[i][j] != g[t.x][t.y]){//如果高度不相等
if(g[i][j] > g[t.x][t.y]) has_higher = true;
else has_lower = true;
}else if(!st[i][j]){//如果高度相等
st[i][j] = true;//标记为走过
q[++ tt] = new PII(i, j);//存入队列
}
}
}
}
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for(int i = 0; i < n; i ++){
for(int j = 0; j < n; j ++){
g[i][j] = sc.nextInt();
}
}
int peak = 0;
int vally = 0;
for(int i = 0; i < n; i ++){
for(int j = 0; j < n; j ++){
if(!st[i][j]){//如果没走过
has_higher = false;
has_lower = false;
bfs(i, j);
if(!has_lower) vally ++;//只要没有比他矮的,那么他就是山谷
if(!has_higher) peak ++;//只要没有比他高的,那么就是山峰
}
}
}
System.out.print(peak + " " + vally);
}
}
最短路问题
844. 走迷宫 - AcWing题库 是迷宫问题的简单版(迷宫问题要存路径)
1076. 迷宫问题 - AcWing题库
import java.util.*;
import java.io.*;
class PII{
int x, y;
public PII(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main{
static int N = 1010, M = N * N, n;
static int[][] g = new int[N][N];
static PII[] q = new PII[M];
static PII[][] pre = new PII[N][N];
public static void bfs(int x, int y){
int hh = 0, tt = -1;
int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};//四个方向
q[++ tt] = new PII(x, y);
pre[x][y] = new PII(0, 0);//终点是由哪个点遍历来的
while(hh <= tt){
PII t = q[hh ++];
for(int i = 0; i < 4; i ++){
int a = t.x + dx[i];
int b = t.y + dy[i];
if(a >= n || b >= n || a < 0 || b < 0) continue;//边界
if(g[a][b] == 1) continue;//墙
if(pre[a][b].x != -1) continue;//如果前一个点的横坐标不为-1,那么说明遍历过
q[++ tt] = new PII(a, b);//加入队列
pre[a][b] = t;//这个点是由上一点过来的标记一下
}
}
}
public static void main(String[] args)throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
for(int i = 0; i < n; i ++){
String[] str = br.readLine().split(" ");
for(int j = 0; j < n; j ++){
g[i][j] = Integer.parseInt(str[j]);
pre[i][j] = new PII(-1, -1);//标记为没遍历过
}
}
bfs(n - 1, n - 1);//倒着来遍历
PII end = new PII(0, 0);//输出路径
while(true){
System.out.println(end.x + " " + end.y);
if(end.x == n - 1 && end.y == n - 1) break;
end = pre[end.x][end.y];
}
}
}
188. 武士风度的牛 - AcWing题库
import java.util.*;
import java.io.*;
class PII{
int x, y;
public PII(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main{
static int N = 200, M = N * N;
static int n, m;
static char[][] g = new char[N][N];
static PII[] q = new PII[M];
static int[][] dist = new int[N][N];
public static int bfs(int a, int b){
int hh = 0, tt = -1;
int[] dx = {-2, -2, -1, 1, 2, 2, 1, -1};//八个方向
int[] dy = {-1, 1, 2, 2, 1, -1, -2, -2};
q[++ tt] = new PII(a, b);//加入队列
dist[a][b] = 0;
while(hh <= tt){
PII t = q[hh ++];
for(int i = 0; i < 8; i ++){
int x = t.x + dx[i];
int y = t.y + dy[i];
if(x >= n || y >= m || x < 0 || y < 0) continue;//边界
if(dist[x][y] != -1) continue;//如果走过了
if(g[x][y] == '*') continue;//障碍
if(g[x][y] == 'H') return dist[t.x][t.y] + 1;//到达目标
dist[x][y] = dist[t.x][t.y] + 1;//步数加1
q[++ tt] = new PII(x, y);//加入队列
}
}
return -1;
}
public static void main(String[] args)throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
m = Integer.parseInt(s[0]);
n = Integer.parseInt(s[1]);
for(int i = 0; i < n; i ++){
String str = br.readLine();
char[] arr = str.toCharArray();
for(int j = 0; j < m; j ++){
g[i][j] = arr[j];
dist[i][j] = -1;//标记为没有走过
}
}
for(int i = 0; i < n; i ++){
for(int j = 0; j < m; j ++){
if(g[i][j] == 'K'){
System.out.print(bfs(i, j));
}
}
}
}
}
1100. 抓住那头牛 - AcWing题库
import java.util.*;
public class Main{
static int N = 200010, n, k;
static int[] dist = new int[N];
static int[] q = new int[N];
public static int bfs(){
int hh = 0, tt = -1;
q[++ tt] = n;
dist[n] = 0;
Arrays.fill(dist, -1);//初始化表示没来过
while(hh <= tt){
int t = q[hh ++];
if(t == k) return dist[k] + 1;//到达终点,结果加1
if(t - 1 >= 0 && dist[t - 1] == -1){
dist[t - 1] = dist[t] + 1;
q[++ tt] = t - 1;
}
if(t + 1 < N && dist[t + 1] == -1){
dist[t + 1] = dist[t] + 1;
q[++ tt] = t + 1;
}
if(2 * t < N && dist[2 * t] == -1){
dist[2 * t] = dist[t] + 1;
q[++ tt] = 2 * t;
}
}
return -1;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
System.out.print(bfs());
}
}