网易面试题之逃出地牢

地牢逃脱

题目描述

给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (x0 , y0 ) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一些指定的步长遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上。地牢的出口可能在任意某个可以通行的位置上。牛牛想知道最坏情况下,他需要多少步才可以离开这个地牢。

输入描述:

每个输入包含 1 个测试用例。每个测试用例的第一行包含两个整数 n 和 m(1 <= n, m <= 50),表示地牢的长和宽。接下来的 n 行,每行 m 个字符,描述地牢,地牢将至少包含两个 '.'。接下来的一行,包含两个整数 x0, y0,表示牛牛的出发位置(0 <= x0 < n, 0 <= y0 < m,左上角的坐标为 (0, 0),出发位置一定是 '.')。之后的一行包含一个整数 k(0 < k <= 50)表示牛牛合法的步长数,接下来的 k 行,每行两个整数 dx, dy 表示每次可选择移动的行和列步长(-50 <= dx, dy <= 50)

输出描述:

输出一行一个数字表示最坏情况下需要多少次移动可以离开地牢,如果永远无法离开,输出 -1。以下测试用例中,牛牛可以上下左右移动,在所有可通行的位置.上,地牢出口如果被设置在右下角,牛牛想离开需要移动的次数最多,为3次。

示例1

输入

复制

3 3
...
...
...
0 1
4
1 0
0 1
-1 0
0 -1

输出

复制

3

解题思路:

这是一个广度搜索(bfs)的题目,不同于我们以前做过的迷宫问题,每次走的方法不止上下左右四种,而是由题目给定的k种走法。

题目难点:

1、理解题目意思:当存在一个点不为x时,如果不能到达该点则返回-1。如果所有为”.“的点都能到达,则找出step步数最大的点输出即可。

解题算法思路:我们定义point的内部类,存放点的位置x,y,到该点的步数:step,该点是否可以到达:couldViste,当step为-1时证明该点还没有被经过。

我们将起始点放入队列中,然后从队列中取出第一个元素进行步数的遍历:

如果map[x1][y1]能够到达,且step<map[x1][y1].step或者map[x1][y1].step=-1(该点还没走过),那么我们就更新该点,并把该点加入到我们的优先队列中,循环执行,直到队列为空即可。。

PS:笔者采用的是优先队列(普通队列也可以,因为bfs为先进先出,对于step来说,就是按照步数依次入队的,为了练习java se 所以笔者选择了优先队列)。

解题代码:

import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;

import org.omg.CosNaming.NamingContextExtPackage.AddressHelper;

public class Main {
	class Point{
		int x;
		int y;
		boolean visted ;
		boolean couldViste;
		int step = 0;
		public Point() {
			// TODO Auto-generated constructor stub
			super();
		}
	} 
	Point [][]map ;
	//优先级队列,默认排序即可
	PriorityQueue<Point> queue;
	int [] 	dx;
	int []	dy;
	int n,m,sx,sy;
	int k;
	int resualt;
	public static void main(String[] args) {
		Main main2 = new Main();
		//Point point = new Main2().new Point();
		//内部类的加载
		//Point point = new Main2().new Point();
		main2.init();
	}
	//判断是否符合条件
	private boolean isAdd(int x,int y,int step) {
		//如果能够走,则判断步数,当该点的步数小于此点的步数或者该点没有走过时,更新,并且压入栈中,
		//否则返回false
		boolean judge = false;
		if(x>=0&&x<n&&y>=0&&y<m) {
			//判断是否可以走,更新到该点步数的最小值
			if(map[x][y].couldViste&&(map[x][y].step>step||map[x][y].step==-1)) {
				//System.out.println(map[x][y].step+" step="+step);
				map[x][y].step = step;
				judge = true;
			}
		}
		return judge;
	}
	//进行求解
	private <T> void init() {
		Scanner in = new Scanner(System.in);
		n	=	in.nextInt();
		m	=	in.nextInt();
		map = new Point[n][m];
		for(int i = 0 ;i<n;i++) {
			String row = in.next();
			for(int j = 0 ; j<m;j++) {
				map[i][j] = new Point();
				map[i][j].x = i;
				map[i][j].y = j;
				map[i][j].couldViste = row.charAt(j)=='.';
				map[i][j].visted = false;	
				map[i][j].step = -1;
			}
		}
		sx = 0;
		sy = 0;
		sx = in.nextInt();
		sy = in.nextInt();
		map[sx][sy].visted = true;
		map[sx][sy].step = 0;
		k = in.nextInt();
		dx = new int[k];
		dy = new int[k];
		
		//我们的行走方法
		for(int i = 0 ;i<k;i++) {
			dx[i] = in.nextInt();
			dy[i] = in.nextInt();
		}
		//优先级队列的表示方法,采用了lambda表达式 java8标准,代码块复用
		queue = new PriorityQueue<Point>((p1,p2)->{
						return p1.step<=p2.step? -1:1;}
				);
		queue.add(map[sx][sy]);
		resualt = -1;
		while(!queue.isEmpty()) {
			Point point = queue.poll();
			//System.out.println(point.step+" => x="+point.x+" y = "+point.y);
			for(int i = 0 ;i<k;i++) {
				int x1 = point.x + dx[i];
				int y1 = point.y + dy[i];
				if(isAdd(x1, y1, point.step+1)) {
					resualt = resualt > point.step+1? resualt : point.step+1;
					//System.out.println("x="+x1+" y= "+y1);
					queue.add(map[x1][y1]);
				}
			}
		}
		boolean judge =true;
		for(int i = 0;i<n&&judge;i++) {
			for(int j = 0 ;j<m;j++) {
				if(map[i][j].couldViste==true&&map[i][j].step==-1) {
					//System.out.println("x="+i+" y= "+j);
					resualt = -1;
					judge = false;
					break;
				}
			}
		}
		System.out.println(resualt);
		in.close();
	}
}








 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值