2024-01-30(树与图的深度优先遍历、广度优先遍历、拓扑排序)-CSDN博客
2024-01-31(最短路径)-CSDN博客
多源BFS
173. 矩阵距离 - AcWing题库
求出每个位置到所有为1的点的最短距离
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 char[][] g = new char[N][N];
static int[][] dist = new int[N][N];
static PII[] q = new PII[M];
public static void bfs(){
int hh = 0, tt = -1;
for(int i = 0; i < N; i ++){
Arrays.fill(dist[i], -1);//标记为没走过
}
for(int i = 0; i < n; i ++){
for(int j = 0; j < m; j ++){
if(g[i][j] == '1'){
dist[i][j] = 0;//所有为1的点都置为0
q[++ tt] = new PII(i, j);//把所有起点都加入队列
}
}
}
int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};//四个方向
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 < 0 || b < 0 || a >= n || b >= m) continue;//边界
if(dist[a][b] != -1) continue;//如果走过了
dist[a][b] = dist[t.x][t.y] + 1;//距离加上1
q[++ tt] = new PII(a, b);
}
}
}
public static void main(String[] args)throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
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];
}
}
bfs();
for(int i = 0; i < n; i ++){
for(int j = 0; j < m; j ++){
bw.write(dist[i][j] + " ");
}
bw.write("\n");
}
bw.flush();//关闭流
}
}
最小步数模型
1107. 魔板 - AcWing题库
import java.util.*;
class PII{
char opera;
String str;
public PII(char opera, String str){
this.opera = opera;
this.str = str;
}
}
public class Main{
static char[][] g = new char[2][4];
static Map<String, Integer> dist = new HashMap<>();//到达某个状态要走的距离
static Map<String, PII> pre = new HashMap<>();//某个状态的由哪个状态经过abc哪个步骤来的
static Queue<String> q = new LinkedList<>();//队列
//将字符串转化为二维
public static void set(String t){
for(int i = 0; i < 4; i ++) g[0][i] = t.charAt(i);
for(int i = 0; i < 4; i ++) g[1][i] = t.charAt(7 - i);
}
//将二维转化为字符串
public static String get(){
String res = "";
for(int i = 0; i < 4; i ++) res += g[0][i];
for(int i = 3; i >= 0; i --) res += g[1][i];
return res;
}
//交换上下两行
public static String move1(String t){
set(t);
for(int i = 0; i < 4; i ++){
char temp = g[0][i];
g[0][i] = g[1][i];
g[1][i] = temp;
}
return get();
}
//最右边一列插入到最左边
public static String move2(String t){
set(t);
char a = g[0][3];
char b = g[1][3];
for(int i = 3; i >= 1; i --){
g[0][i] = g[0][i - 1];
g[1][i] = g[1][i - 1];
}
g[0][0] = a;
g[1][0] = b;
return get();
}
//顺时针旋转
public static String move3(String t){
set(t);
char temp = g[0][1];
g[0][1] = g[1][1];
g[1][1] = g[1][2];
g[1][2] = g[0][2];
g[0][2] = temp;
return get();
}
public static int bfs(String start, String end){
if(start.equals(end)) return 0;
q.offer(start);
dist.put(start, 0);
while(!q.isEmpty()){
String t = q.poll();
String[] m = new String[3];
m[0] = move1(t);//abc三个步骤
m[1] = move2(t);
m[2] = move3(t);
for(int i = 0; i < 3; i ++){
if(dist.containsKey(m[i])) continue;
dist.put(m[i], dist.get(t) + 1);
if(pre.containsKey(m[i])) continue;
pre.put(m[i], new PII((char)('A' + i), t));
q.offer(m[i]);
if(m[i].equals(end)) return dist.get(end);
}
}
return -1;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String start = "12345678";
String end = "";
for(int i = 0; i < 8; i ++){
end += sc.next();
}
System.out.println(bfs(start, end));//步骤数
String res = "";//步骤答案
String ans = end;
while(!ans.equals(start)){//由end倒推回start
res += pre.get(ans).opera;
ans = pre.get(ans).str;
}
for(int i = res.length() - 1; i >= 0; i --){
System.out.print(res.charAt(i));
}
}
}
双端队列广搜
175. 电路维修 - AcWing题库
这里由于起点(0,0)的横纵坐标是偶数,因为走的是斜线,所以到达的点也一定是偶数。
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 = 510, n, m, INF = 0x3f3f3f3f;
static char[][] g = new char[N][N];
static int[][] dist = new int[N][N];
static boolean[][] st = new boolean[N][N];
static int[] dx = {-1, -1, 1, 1}, dy = {-1, 1, 1, -1};//四个行进方向
static int[] ix = {-1, -1, 0, 0}, iy = {-1, 0, 0, -1};//行进方向上面的斜杠的坐标
static char[] s = {'\\', '/', '\\', '/'};
public static int bfs(){
//由于有多组测试数据,所以每次都要初始化
for(int i = 0; i < N; i ++){
Arrays.fill(st[i], false);
Arrays.fill(dist[i], INF);
}
Deque<PII> q = new LinkedList<>();//双端队列
dist[0][0] = 0;
q.addLast(new PII(0, 0));
while(!q.isEmpty()){
PII t = q.pollFirst();
int x = t.x;
int y = t.y;
if(x == n && y == m) return dist[x][y];//等于终点的时候,返回距离
if(st[x][y]) continue;//遍历过了
st[x][y] = true;
for(int i = 0; i < 4; i ++){
int a = x + dx[i];
int b = y + dy[i];
if(a < 0 || b < 0 || a > n || b > m) continue;//越界
int ga = x + ix[i];
int gb = y + iy[i];
int w = (g[ga][gb] == s[i]) ? 0 : 1;//看一下能不能走,能走变0,不能走变1
if(dist[a][b] > dist[x][y] + w){
dist[a][b] = dist[x][y] + w;//如果下一步的距离小于这个点新点的距离,那就更新
}
if(w == 0) q.addFirst(new PII(a, b));//如果是0,放在队头
else q.addLast(new PII(a, b));//如果不是0,放在队尾
}
}
return -1;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while(T -- > 0){
n = sc.nextInt();
m = sc.nextInt();
for(int i = 0; i < n; i ++){
String str = sc.next();
for(int j = 0; j < m; j ++){
g[i][j] = str.charAt(j);
}
}
int t = bfs();
if(t == -1) System.out.println("NO SOLUTION");
else System.out.println(t);
}
}
}