package 第四章;
import java.awt.print.Book;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
public class 层层递进_广度优先搜索 {
static int[][] next = {
{0,1},
{1,0},
{0,-1},
{-1,0}
};
static class Node{
int x;
int y;
int step;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
// public Node(int x,int y,int step) {
// this.x = x;
// this.y = y;
// this.step = step;
// }
}
static int[][] a ;//存储地图
static int[][] book; //标记
public static void main(String[] args) {
Queue<Node> que = new LinkedList<Node>();//存x轴
int head ,tail;
Scanner input = new Scanner(System.in);
int n = input.nextInt();//n行
int m = input.nextInt();//m列
book = new int[n+1][m+1];
a = new int[n+1][m+1];
for (int i = 1; i <=n ; i++) {
for (int j = 1; j <=m; j++) {
a[i][j] = input.nextInt();
}
}
int startx = input.nextInt();//
int starty = input.nextInt();//入口
int endp = input.nextInt();
int endq = input.nextInt();//小哈位置
Node node = new Node();
node.setX(startx);
node.setY(starty);
node.setStep(0);
//队列初始化
head = 1;
tail = 1;
//往队列插入迷宫入口坐标
que.offer(node);
// tail++;//存入之后,头指针可以往下一个 (其实我在想,根本没必要记录,因为que的方法有这一特性) 事实证明不用!
book[startx][starty] = 1;
int flag = 0;//用来记录是否到达目标点,0表示暂时还没有到大,1表示到达了。
//当队列不是空的时候循环
/*
* 在啊哈算法中,判断条件是head<tail
* 然而我们队列方法中的poll()方法取出并删除队头的元素,当队列为空,返回null;
* 会自动删除队头元素,
* 所以我们只需要判断条件为各个队列是否为空就好。
*/
// while (!quex.isEmpty()&&!quey.isEmpty()&&!quef.isEmpty()&&!ques.isEmpty()) {
while (!que.isEmpty()) {
//枚举四个方向
for (int i = 0; i < 4; i++) {
//计算下一个坐标
// peek()方法直接取出队头的元素,并不删除.
int next_x = que.peek().getX() + next[i][0];
int next_y = que.peek().getY() + next[i][1];
//判断是否越界
if (next_x<1||next_x>n||next_y<1||next_y>m) {
continue;
}
//判断是否是障碍物或者已经在路径中
if (a[next_x][next_y]==0 && book[next_x][next_y]==0) {
//要记录这个点是否已经走过,
//要注意广搜的每个点只入队一次,所以和深搜一同,不需要将Book数组还原!!
book[next_x][next_y] = 1;
//插入新的点到队列中
//(个人注释:我认为要先插入再删除,因为这样保证了队列一直不为空)
Node node2 = new Node();
node2.setX(next_x);
node2.setY(next_y);
node2.setStep(que.peek().getStep()+1);
que.offer(node2);
//下面这语句证明,一定要先插入数据在队列后再让队头出队,因为这语句利用了队头的数据
/*
* 那么,问题来了,那该到哪里才将头的数据删除呢?
* 接下来考虑的是,这是在一个for循环里面,在这个坐标的四个方向都需要进去一下
* 这就意味着,队列是一直在不断扩展的,当扩展完了四个方向,这就意味着这个坐标
* 就已经没用处了!没用不就要将它删除了嘛!所以应该是for之外删除!
*/
// ques.offer(ques.peek()+1);
// ques.remove();
// tail++;(这个同上Head)
}
//如果到了目标点了,停止扩展,任务结束,退出循环
if (next_x == endp && next_y == endq) {
//注意下面两句话的位置不能写颠倒了
flag = 1;
break;
}
}
if (flag == 1) break;
head++;//注意这地方千万不要忘记,当一个点跨站结束之后,head++才能对后面的
//点再进行扩展
/*
* 其实就是这里,啊哈算法中的head++就是删除,但是我认为他这样的删除就只是不去看它,实际上还是在内存里
* 所以我们要删除,用:remove()方法直接删除队头的元素:
*/
que.remove();
}
//打印你队列中末尾最后一个点的步数
//注意tail是指想队列队列(即最后一个位)的下一个位置,所以这需要-1
/*
* 啊哈算法中,有位置可以get到队列的东西,但是que好像没有,都是取队头的东西
* 我所以我用了下面很笨拙的方法:
* 假设队列有10 长度,那我就删除队头9次不就剩下最后一个嘛?
*/
/*
*
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3
*/
//这个是因为不能立即取出队尾,所以通过这个remove队头,当队列的长度为一,就是队尾啦!
while (que.size()!=1) {
que.remove();
}
System.out.println(que.peek().getStep());
}
}
请多多指教!