如何找到迷宫出口

一、问题描述

给出如下的矩阵

1 1 1 1

0 0 0 1

1 9 0 0

1 1 1 1

其中1代表此位置是可以通过的,0代表此位置是不可通过的,要从起点开始,确定是否存在这样一条路径,可以从起点找到数字9。也就是找到这样一条路径1->1->1 ...... ->9。这个问题是寻找迷宫出口的变形。可以将9看成是迷宫的出口,而给出的开始位置是迷宫的入口,寻找一条路径。

二、问题求解

当矩阵阶数不是太大的时,可以使用递归来求解,但是,当矩阵的阶数变得很大时,则需要使用另外的方法进行计算,也就是采用栈来进行求解。

下面是两种解决方法

1.当矩阵阶数较小时,采用递归进行求解,这种方式只是用来开拓思路,解此问题存在一定的局限性。

源代码如下:

import java.util.Scanner;
public class MatrixPath {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		String line = scan.nextLine();	//输入行和列
		String[] lines = line.split("\\s+");//分离行和列
		int row = Integer.parseInt(lines[0]);
		int col = Integer.parseInt(lines[1]);

		int[][] matrix = new int[row + 2][col + 2];	//将外层包围一层0元素
		footPrints = new boolean[row + 2][col + 2];
		endPrints = new boolean[row + 2][col + 2];  

		for(int i = 0; i < row; i++) {	//初始化数组元素
			line = scan.nextLine();
			lines = line.split("\\s");
			for(int j = 0; j < lines.length; j++) {
				matrix[i + 1][j + 1] = Integer.parseInt(lines[j]);
			}
		}

		scan.close();

		int startX = 1;	//入口横坐标
		int startY = 1;	//入口纵坐标

		System.out.println(exsitPath(startX, startY, row, col, matrix) + " ");
	}

	public static boolean exsitPath(int x, int y, int row, int col, int[][] matrix) {
		if(x < 0 || y < 0 || x >= row || y >= col)
			return false;
		if(matrix[x][y] == 9)
			return true;
		if(matrix[x][y] == 0)
			return false;
		if(exsitPath(x + 1, y, row, col, matrix) || exsitPath(y - 1, x, row, col, matrix) || exsitPath(x, y - 1, row, col, matrix) || exsitPath(x, y + 1, row, col, matrix))
			return true;
		return false;
	}
}

测试用例:

3 3
1 1 1
1 9 1
0 1 1

输出结果为:true

测试用例:

4 4
1 1 1 1
0 0 0 1
0 0 1 1
9 1 1 1

输出结果:java.lang.StackOverflowError,堆栈溢出

2.使用递归的方法要选择好测试用例,很可能因为测试用例的选取不恰当而造成堆栈溢出。递归只是为了开拓思路而已,下面使用栈结构来解决堆栈溢出的问题。

源代码如下:

package com.leesf.Main;

import java.util.ArrayList;
import java.util.Scanner;

class Position {//位置信息
    private int x;
    private int y;
    
    public Position(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
}

class Item {//栈中元素类型
    private int order;    //第几步
    private Position seat;    //位置
    private int value;    //对应的值
    private int di;    //方位
    
    public Item(int order, Position seat, int value, int di) {
        this.order = order;
        this.seat = seat;
        this.value = value;
        this.di = di;
    }
    
    public int getOrder() {
        return order;
    }
    
    public Position getSeat() {
        return seat;
    }
    
    public int getDi() {
        return di;
    }
    
    public int getValue() {
        return value;
    }
    
    public void setDi(int di) {
        this.di = di;
    }
    
}

class MyStack<T> {//定义栈结构
    private static int index = -1;
    private ArrayList<T> array;
    public MyStack() {
        array = new ArrayList<T>();
    }
    
    public void push(T item) {    
        array.add(item);
        index++;
    }
    
    public T pop() {
        T result = array.get(index);
        array.remove(index);
        index--;
        return result;
    }
    
    public boolean isEmpty() {
        if(index != -1)
            return false;
        else
            return true;
    }
}

public class MatrixPath {
    private static boolean[][] footPrints;    //留下脚印
    private static boolean[][] endPrints;    //留下不能通过印记
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String line = scan.nextLine();    //输入行和列
        String[] lines = line.split("\\s+");//分离行和列
        int row = Integer.parseInt(lines[0]);
        int col = Integer.parseInt(lines[1]);
        
        int[][] matrix = new int[row + 2][col + 2];    //将外层包围一层0元素
        footPrints = new boolean[row + 2][col + 2];
        endPrints = new boolean[row + 2][col + 2];  
        
        for(int i = 0; i < row; i++) {    //初始化数组元素
            line = scan.nextLine();
            lines = line.split("\\s");
            for(int j = 0; j < lines.length; j++) {
                matrix[i + 1][j + 1] = Integer.parseInt(lines[j]);
            }
        }
        
        scan.close();
        
        int startX = 1;    //入口横坐标
        int startY = 1;    //入口纵坐标
        
        System.out.println(exsitPath(startX, startY, row, col, matrix) + " ");

//System.out.println(exsitPath(startX, startY, matrix) + " ");    
    }
    
    //判断是否存在路径
    public static boolean exsitPath(int x, int y, int[][] matrix) {
        
        MyStack<Item> stack = new MyStack<Item>();
        //当前的位置
        Position curPos = new Position(x, y);
        //开始第一步
        int curStep = 1;
      
        do {
            if(pass(curPos, matrix)) { //该位置是可通过的
                System.out.println("x - y = " + curPos.getX() + " - " + curPos.getY());
                footPrint(curPos);//留下脚印
                Item item = new Item(curStep, curPos, matrix[curPos.getX()][curPos.getY()], 1);
                stack.push(item);//将该可通位置放入栈中
                if(item.getValue() == 9) {//如果已经找到目标,则返回
                    System.out.println("总共花费了" + curStep + "步, 找到目标");
                    return true;
                }
                curPos = nextPos(curPos, 1);//试探下一步,即东边的,但是不放入栈中
                curStep++;//步数加1
                
            } else {//改位置不可通过
                if(!stack.isEmpty()) {//栈不为空
                    Item item = stack.pop();//出栈
                    while(item.getDi() == 4 && !stack.isEmpty()) {//留下了脚印的个数加上不可通过的个数之和为4,进行出栈处理
                        markPrint(item.getSeat());//留下不可通过印记并进行出栈处理
                        item = stack.pop();//出栈
                    }
                    if(item.getDi() < 4) {//四个方向还未试探完
                        item.setDi(item.getDi() + 1);//换下一个方向进行试探
                        stack.push(item);//入栈
                        curPos = nextPos(item.getSeat(), item.getDi());//试探下一个位置
                    }
                }
            }
        } while(!stack.isEmpty());    
        System.out.println("总共花费了" + curStep + "步,没有找到目标");
        return false;
    }
    
    public static boolean pass(Position curPos, int[][] matrix) {
        if(matrix[curPos.getX()][curPos.getY()] != 0 && endPrints[curPos.getX()][curPos.getY()] == false && footPrints[curPos.getX()][curPos.getY()] == false)
            return true;
        else
            return false;
    }
    
    public static void footPrint(Position curPos) {
        footPrints[curPos.getX()][curPos.getY()] = true;
    }
    
    public static Position nextPos(Position curPos, int di) {
        int x = curPos.getX();
        int y = curPos.getY();
        switch(di) {
        case 1: {
            y = curPos.getY() + 1; //东
        }
        break;
        case 2: {
            x = curPos.getX() + 1; //南
        }
        break;
        case 3: {
            y = curPos.getY() - 1; //西
        }
        break;
        case 4: {
            x = curPos.getX() - 1; //北
        }
        break;
        
        }
        
        return new Position(x, y);
    }
    
    public static void markPrint(Position seat) {
        endPrints[seat.getX()][seat.getY()] = true;
    }
}

测试用例:

4 4
1 1 1 1
0 0 0 1
0 0 1 1
9 1 1 1

输出结果:

x - y = 1 - 1
x - y = 1 - 2
x - y = 1 - 3
x - y = 1 - 4
x - y = 2 - 4
x - y = 3 - 4
x - y = 4 - 4
x - y = 4 - 3
x - y = 4 - 2
x - y = 4 - 1
总共花费了10步, 找到目标
true

测试用例:

8 8
1 1 0 0 0 0 1 1
1 1 0 0 0 0 0 0
0 1 1 1 1 0 0 0
1 1 1 1 0 0 0 0
0 1 0 0 1 1 1 1
0 1 1 9 0 0 0 0
0 0 0 0 0 0 0 0
1 0 1 0 1 1 1 1

输出结果:

x - y = 1 - 1
x - y = 1 - 2
x - y = 2 - 2
x - y = 3 - 2
x - y = 3 - 3
x - y = 3 - 4
x - y = 3 - 5
x - y = 4 - 4
x - y = 4 - 3
x - y = 4 - 2
x - y = 5 - 2
x - y = 6 - 2
x - y = 6 - 3
x - y = 6 - 4
总共花费了14,步, 找到目标
true

测试用例:

4 4
1 0 0 1
1 1 1 1
0 0 1 0
1 1 1 1

输出结果:

x - y = 1 - 1
x - y = 2 - 1
x - y = 2 - 2
x - y = 2 - 3
x - y = 2 - 4
x - y = 1 - 4
x - y = 3 - 3
x - y = 4 - 3
x - y = 4 - 4
x - y = 4 - 2
x - y = 4 - 1
总共花费了12步,没有找到目标
false

三、总结

  两种方法完成了问题的解决,当然,递归的方法只是用来扩展思路,其实,使用递归并且记录之前已经遍历到一些信息也是可以完成问题的解答,这就涉及到了动态规划。这就交给读者去完成啦。

  好了,谢谢各位观看,我们下期再会。

时间: 2024-10-05 22:29:50

如何找到迷宫出口的相关文章

迷宫问题一 找到迷宫的一条路径(DFS+回溯)

问题描述: 一天,小明不小心进入了一个迷宫,现在请你帮助他判断能否出走出迷宫,如果可能,则输出YES. 如果不能走到出口,则输出NO. 每次走只能是上下左右4个方向. *表示可走 #表示障碍 T表示出口 入口是(1,1),数据保证左上角是入口 #include<iostream> using namespace std; char maze[100][100]; bool flag[100][100]; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; int

猫和老鼠的迷宫问题

题目如下: 用一个10行10列的二维平面表格表示迷宫,左上角作为迷宫的入口,右下角作为迷宫的出口.设迷宫中有一只猫在随机游走,一只老鼠要从迷宫的入口逃到出口.如果老鼠遇到猫就会被吃掉.假定老鼠和猫的速度是相同的,而且猫不会主动搜寻老鼠.问题求解的目标是老鼠寻找一条从入口到出口的通路,并且不会被猫吃掉,写出问题的求解规则.(心形为老鼠初始位置,菱形为猫初始位置,五角星为迷宫出口) 这是人工智能导论课堂上老师留的一道作业题,课堂展示之后,为了不想让自创的解题思路就这样隐没,于是决定浪费一些时间写成博

迷宫问题算法设计与实现

迷宫求解 求迷宫中从入口到出口的所有路径是一个经典的程序设计问题.由于计算机解迷宫时,通常用的是"穷举求解"的方法,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走:否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止.为了保证在任何位置上都能沿原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径.因此,在求迷宫通路的算法中应用"栈"也就是自然而然的事了.  假设迷宫如下图所示: 1 1 1 1 1 1 1 1 1 0 1 1

程序设计项目十三

程序设计项目十三 编写左手逃生法则演示程序.参看demo7.gif示例. 提示: (1)地图中只有三种元素:墙.通道.出口.设计地图时,要给不同的元素赋予不同的编码. (2)什么情况下改变行进的方向.遇到这些情况后根据当前方向决定下一步方向变化的规律是什么. (3)左手逃生法则简述:在一个有出入口,没有回路的迷宫中,一直保持左手贴着墙壁向前走,总能找到迷宫出口. 代码: 有问题,,, 1 assume cs:code 2 map segment 3 db 1,1,1,1,0,0,0,0,0,0,

迷宫问题求解(一)利用栈与递归求解出口

本文适合于对迷宫问题已有初步研究,或阅读代码能力较强的人. 因此,如果你对迷宫问题一无所知,请参考其他更详细的资料. 迷宫问题,是一个对栈(Stack)典型应用的例子之一. 假如,有如下10X10的迷宫(0代表通路,1代表障碍),我们需要用写程序来找出迷宫的出口. 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 0 1 0 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 1 1 1 1 0 0

BFS求解迷宫最短路径

本文使用BFS广度优先搜索算法实现求解迷宫的最短路径(C++),使用到了队列先进先出的性质,依次搜索路径直到找到目标出口(如果迷宫能走通)求解到的路径即为该迷宫的最短路径,找到返回true,找不到返回false,本文使用vexmap一个map容器记录队列的搜索路径(记录队列路径的实现有点草率,可以再优化).</p><p> </p><pre class="cpp" name="code">#include<iost

回溯法找迷宫最短路径

有一个二维数组,0表示路,-1表示墙,求其中任意两点的最短路径 我们先看,怎么求一条路径:求两点路径是一个数据结构上的典型的迷宫问题,解决办法如下: 从一点开始出发,向四个方向查找(上,右,下,左),每走一步,把走过的点的值+1,防止重复行走,并把走过的点压入堆栈(表示路径),如果遇到墙.或者已走过的点则不能前进,如果前方已经无路可走,则返回,路径退栈,这样递归调用,直到找到终点为止. 如果我们调整查找的顺序,改为左.右.上.下,可能会得到更短的路径,但这种方法不能保证一定是最短路径. 经过网上

Java数据结构之回溯算法的递归应用迷宫的路径问题

一.简介 回溯法的基本思想是:对一个包括有很多结点,每个结点有若干个搜索分支的问题,把原问题分解为对若干个子问题求解的算法.当搜索到某个结点.发现无法再继续搜索下去时,就让搜索过程回溯(即退回)到该结点的前一结点,继续搜索这个结点的其他尚未搜索过的分支:如果发现这个结点也无法再继续搜索下去时,就让搜索过程回溯到这个结点的前一结点继续这样的搜索过程:这样的搜索过程一直进行到搜索到问题的解或搜索完了全部可搜索分支没有解存在为止. 该方法可以使用堆栈实现.也可以使用递归实现,递归实现的话代码比较简单,

遍历迷宫

走迷宫 1 #include<stdio.h> 2 #define MAXSIZE 15 3 char point[MAXSIZE][MAXSIZE]={ 4 {'X','X','X','X','X','X','X','X','X','X','X','X','X','X','X'}, 5 {' ','o','o','o','o','o','X','o','o','X','o','o','o','o','X'}, 6 {'X','o','X','o','X','X','X','X','o','X