蓝桥杯算法提高试题 学霸的迷宫(BFS)


问题描述

  学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗。但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫。因为班长还有妹子要陪,磨刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线。可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线。


输入格式

  第一行两个整数n, m,为迷宫的长宽。
  接下来n行,每行m个数,数之间没有间隔,为0或1中的一个。0表示这个格子可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫的出口在(n,m)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)可以通过。


输出格式

  第一行一个数为需要的最少步数K。
  第二行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。


样例输入

Input Sample 1:
3 3
001
100
110

Input Sample 2:
3 3
000
000
000


样例输出

Output Sample 1:
4
RDRD

Output Sample 2:
4
DDRR


数据规模和约定
  有20%的数据满足:1<=n,m<=10
  有50%的数据满足:1<=n,m<=50
  有100%的数据满足:1<=n,m<=500。


解题思路:

  一般求最短路径或者是最少步骤,都可以用BFS解决;这题还有最小字典序的要求,只需要在遍历时优先走字典序小的方向即可;记录路径的问题,可以在属性里添加一个方向的属性,即表示这个点哪一个方向走来的,并且在节点里设置一个节点的引用pre,用于表示这个节点的上一个节点是谁。


解题代码:

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 学霸迷宫__BFS {
	static int n; //迷宫的行数
	static int m; //迷宫的列数
	static char[][] grash; 	//迷宫地图
	static char[][] visite;	//表记访问过的位置
	static Queue<Node> q = new LinkedList<Node>();	//用存储广度搜索
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		n = scanner.nextInt();
		m = scanner.nextInt();
		grash = new char[n][m];
		visite = new char[n][m];
		//读取地图信息
		for(int i=0; i<n; i++){
			String temp = scanner.next();
			grash[i] = temp.toCharArray();
		}
		visite = grash;		
		
		Bfs();
		
	}

	//广度收搜
	private static void Bfs() {
		q.add(new Node(0,0,0,'S',null));  //将人口位置加入队列
		while(!q.isEmpty()){
			Node node = q.poll(); //将对首的节点弹出
			int i = node.x;
			int j = node.y;
			int d = node.depth;
			//判断是否到达终点
			if(i==n-1 && j==m-1){
				System.out.println(d);
				print(node);  //打印路径
				break;
			}
			// 请注意在字典序中D<L<R<U 也就是说:顺序应该是下,左,右,上
			//向下走, 判断是否出界, 是否走过, 是否能走
			if(i+1<grash.length && visite[i+1][j]!='1' && grash[i+1][j]!='1'){
				q.add(new Node(i+1, j, d+1, 'D', node));
				visite[i+1][j] = '1';
			}
			//向左走
			if(j-1>=0 && visite[i][j-1]!='1' && grash[i][j-1]!='1'){
				q.add(new Node(i, j-1, d+1, 'L', node));
				visite[i][j-1] = '1';
			}
			//向右走
			if(j+1<grash[0].length && visite[i][j+1]!='1' && grash[i][j+1]!='1'){
				q.add(new Node(i, j+1, d+1, 'R', node));
				visite[i][j+1] = '1';
			}
			//向上走
			if(i-1>=0 && visite[i-1][j]!='1' && grash[i-1][j]!='1'){
				q.add(new Node(i-1, j, d+1, 'U', node));
				visite[i-1][j] = '1';
			}
		}
	}

	//打印路径
	private static void print(Node node) {
		StringBuilder sb = new StringBuilder();
		sb.append(node.direction);
		Node temp = node.pre;
		while(temp.pre!=null){  //因为开始节点是没有方向记录的,所以不需要打印开始节点的方向
			sb.append(temp.direction);
			temp = temp.pre;
		}
		sb = sb.reverse();  //将字符串翻转,因为存储的时候是反向存储的
		System.out.println(sb.toString());
	}
}

class Node{
	int x;
	int y;
	int depth; //表示走到这个节点需要几步
	char direction;	//用于记录路径,表示上一个节点时从那一个方向走到这个节点的
	Node pre;  //表示上一个节点,即是从那一个节点走到这个节点的
	
	public Node() {
	}
	
	public Node(int x, int y, int depth) {
		super();
		this.x = x;
		this.y = y;
		this.depth = depth;
	}
	
	public Node(int x, int y, int depth, char direction, Node pre) {
		super();
		this.x = x;
		this.y = y;
		this.depth = depth;
		this.direction = direction;
		this.pre = pre;
	}
}

测试结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/106784697
今日推荐