Problem Description
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?
Input
第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符’.‘表示该位置为空地,字符’*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
Output
每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
Sample Input
2
5 5
…**
*..
…
…
…
1 1 1 1 3
5 5
…
*.*.
…
…
*…
2 1 1 1 3
Sample Output
no
yes
首先论对宽搜的认识,学习数据结构之前,一直看不懂什么是宽搜,当时遇到搜索题很是苦恼,只会用回溯法进行深搜,还是利用到了函数运行的机制(类似递归),第一次真正明白宽搜的运行机制是二叉树的遍历,有一种用队列的遍历方式(二叉树链接)才明白宽搜的运行机制,面对这题,深搜超时,可能有的大神优化能过。但是首先想到的应该是宽搜,核心点是转弯的次数。
1:刚开始我打算用boolean数组标记走过的位置,用class新类time表示点的转弯次数,后来错了。想了一想错的原因,右下右转两次,如果下右右只有一次但是晚走而没法走,所以这种想法是错的。
2:用数组标记当前点的最小转弯,如果新点,入队。若果比这个点的转弯次小于等于,也可以入队。这样就能保证最终找到最终答案,但是还是不过,超时。至于原因:楼梯模型(要克服楼梯的走楼梯而不直走的问题)
3:最终处理方案:使用优先队列,(java的需要自己百度学习一下),因为漫天都是C类的代码,教程,我根本不知道那个是优先队列。必须用优先队列优化。后来请教了学长帮我解决。优先队列让小节点先 入队。
wa了28次,第29次终于过了。
代码如下:
import java.util.Comparator; import java.util.PriorityQueue; import java.util.Queue; import java.util.Scanner; /* * bfs 标记节点,计入最小节点 优先队列优化 */ public class 杭电1728bfs { static int a[][]= {{-1,0},{0,1},{1,0},{0,-1}};//左 上 右 下 static boolean judgle=false; public static void main(String[] args) { Scanner sc=new Scanner(System.in); int t=sc.nextInt(); //测试数据 for(int t1=0;t1 q1=new PriorityQueue<>(timecomepare); e[y][x]=-1; q1.add(new zuobiao(x,y)); while(!q1.isEmpty()) { zuobiao exa=q1.peek();//头坐标 q1.poll(); int x1=exa.x;int y1=exa.y; if(x1==x2&&y1==y2){if(exa.time<=k) {judgle=true;break;}} else for(int i=0;i<4;i ) { if(x1 a[i][0]<0||x1 a[i][0]>n-1||y1 a[i][1]<0||y1 a[i][1]>m-1||c[y1 a[i][1]][x1 a[i][0]]==false){}//不能走或者走过 else { zuobiao zuo=new zuobiao(x1 a[i][0],y1 a[i][1],exa.time,exa.fangxiang); zuo.fangxiang=i; if(zuo.fangxiang!=exa.fangxiang) {zuo.time ;} if(e[y1 a[i][1]][x1 a[i][0]]>=zuo.time)//转头次数小于等于,入队 {q1.add(zuo);e[y1 a[i][1]][x1 a[i][0]]=zuo.time;} else if(e[y1 a[i][1]][x1 a[i][0]]==0){//初始的没用过,入队 q1.add(zuo); e[y1 a[i][1]][x1 a[i][0]]=zuo.time; } } } } } public static Comparator timecomepare =new Comparator()//实现comparator接口 { public int compare(zuobiao a1,zuobiao a2) { return (int)(a1.time-a2.time); } }; } class zuobiao { int x; int y; int time; int fangxiang; public zuobiao(int x,int y) { this.x=x; this.y=y; this.fangxiang=-1; this.time=-1; } public zuobiao(int x,int y,int time,int fangxiang) { this.x=x; this.y=y; this.time=time; this.fangxiang=fangxiang; } }