- http://ac.jobdu.com/problem.php?id=1335
- 转自:www.acmerblog.com
- 还有另一题,类似的
- http://ac.jobdu.com/problem.php?id=1365
- 建议用BFS实现较为方便。
- 题目描述:
-
sun所在学校每年都要举行电脑节,今年电脑节有一个新的趣味比赛项目叫做闯迷宫。
sun的室友在帮电脑节设计迷宫,所以室友就请sun帮忙计算下走出迷宫的最少步数。
知道了最少步数就可以辅助控制比赛难度以及去掉一些没有路径到达终点的map。
比赛规则是:从原点(0,0)开始走到终点(n-1,n-1),只能上下左右4个方向走,只能在给定的矩阵里走。
- 输入:
-
输入有多组数据。
每组数据输入n(0<n<=100),然后输入n*n的01矩阵,0代表该格子没有障碍,为1表示有障碍物。
注意:如果输入中的原点和终点为1则这个迷宫是不可达的。
- 输出:
-
对每组输入输出该迷宫的最短步数,若不能到达则输出-1。
- 样例输入:
-
2 0 1 0 0 5 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 1 1 1 0 1 0 1 0 0
- 样例输出:
-
2 8
郁闷啊,一做ACM的比赛题就认栽。总是通过一两个案例。不知道还有什么边界数据没考虑到。
自己测试的案例没有错。
一到ACM就挂了。只通过第一个案例。
哪位高手能指点一下??感激不尽!
经过初步分析:此类简单的迷宫问题是不适合用递归的。java会栈溢出,而且大数据会出错。暂时没发现问题在哪。根据打印结果,递归只是递归了地图的一大部分,而不是全部。
用BFS的话,是遍历了图中全部的节点。起初以为用递归会快些,后来发现还是用BFS比较好。
下面的代码仅供参考,是错误的。
import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;
public class 闯迷宫 {
static int arr[][];
static long opt[][];
static int n;
static final long MAX = 99999999;
static int ori[][] = {{0,1},{0,-1},{1,0},{-1,0}};
public static void main(String[] args) {
Scanner s = new Scanner(new BufferedInputStream(System.in));
while(s.hasNextInt()){
n = s.nextInt();
arr = new int[n][n];
opt = new long[n][n];
for(long[] a:opt)
Arrays.fill(a, MAX);
for(int i=0; i<n; i++){
for(int j=0; j<n; j++)
arr[i][j] = s.nextInt();
}
if(arr[0][0] == 1 || arr[n-1][n-1]==1)
System.out.println(-1);
else{
long t = f(n-1,n-1);
if(t<MAX)
System.out.println(t);
else
System.out.println(-1);
}
// for(long[] ar:opt){
// for(long i:ar)
// System.out.printf("%6d ",i);
// System.out.println();
// }
}
}
static boolean isok(int x,int y){
return x>=0 && x<n && y>=0 && y<n;
}
//动态规划的思想
static long f(int i,int j){
arr[i][j] = 1; //重要的一步。防止无限递归。自己想的办法,不知道是否妥当,请高手指教
if(opt[i][j] < MAX)
return opt[i][j];
if(i==0 && j==0)
return 0;
for(int k=0; k<4; k++){
int x =i + ori[k][0];
int y =j + ori[k][1];
long temp = MAX;
if(isok(x,y) && (arr[x][y]==0||opt[x][y]<MAX )){ //opt[x][y]<MAX(表示已经计算过可以到达的点) 这个判断也很重要。因为上面arr[i][j] = 1会覆盖掉已经计算的点
temp = f(x,y);
if(opt[i][j] > temp + 1)
opt[i][j] = temp +1;
}
}
return opt[i][j];
}
}
/*测试:
6
0 0 0 0 0 1
1 0 1 0 1 1
0 0 0 0 0 1
1 1 1 1 0 1
1 0 0 0 0 1
0 0 0 0 0 010
99999999 1 99999999 99999999 99999999 99999999
99999999 2 99999999 99999999 99999999 99999999
99999999 3 4 5 6 99999999
99999999 99999999 99999999 99999999 7 99999999
99999999 11 10 9 8 99999999
99999999 12 11 10 9 10
*/正确的代码应该在下面,用BFS:
import java.io.BufferedInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static int n;
static int map[][];
static int visit[][];
static Queue<B> q;
static B start, end;
static int ori[][] = {{0,1},{0,-1},{1,0},{-1,0}};
public static void main(String[] args) {
Scanner s = new Scanner(new BufferedInputStream(System.in));
while(s.hasNextInt()){
n = s.nextInt();
map = new int[n][n];
visit = new int[n][n];
q = new LinkedList<B>();
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
map[i][j] = s.nextInt();
if(map[0][0] == 1 || map[n-1][n-1]==1){
System.out.println(-1);
continue;
}
System.out.println(bfs());
}
}
static int bfs(){
B pre = new B(0,0,0);
B next = null;
q.add(pre);
while(!q.isEmpty()){
pre = q.poll();
visit[pre.x][pre.y] = 1;
for(int i=0; i<4; i++){
int x = pre.x + ori[i][0];
int y = pre.y + ori[i][1];
if(x == n-1 && y ==n-1)
return pre.time +1;
if(x>=0 && x<n && y>=0 && y<n && map[x][y]==0 && visit[x][y]==0){
next = new B(x,y,pre.time+1);
q.add(next);
}
}
}
return -1;
}
}
class B{
int x,y,time;
public B(int x, int y, int time) {
super();
this.x = x;
this.y = y;
this.time = time;
}
}