zoukankan      html  css  js  c++  java
  • 用广度优先算法求解迷宫的最短路径(go语言)

    用广度优先算法求解迷宫的最短路径

    迷宫如下:0代表可以通过的路径,1代表墙


    思路

    • 你可以想象你就在迷宫中,你每走的一步的是未知的,例如你走第二步的时候,如果周围都没有墙,你的路径就是这样:
            1
    1      0      1
            1
    
    
    • 下一步就是这样:
                  2
            2    1     2
       2    1    0     1     2
            2    1     2
                  2
    
    • 走到3步:

    所以我们要用一个队列保存上次已经探索的位置,并用相同大小的矩阵记录步数。


    假如我们在探索迷宫

    • 第一步:

    • 第二步:

    • 第三步:

    • 第四步:

    最后生成如下解法:


    解决方案

    我们用1代表墙,0代表可以通过的路径
    初始化迷宫路径如下,保存到文件中,具体怎么读取解析下面有对应的代码:

    6 5
    0 1 0 0 0
    0 0 0 1 0
    0 1 0 1 0
    1 1 1 0 0
    0 1 0 0 1
    0 1 0 0 0

    注意:路径是相对gopath的路径,这个矩阵最后有个换行符(记得加上)


    代码如下,基本上都有注释,多看两遍应该就懂了

    package main
    
    import (
    	"fmt"
    	"os"
    )
    /*
    	author:hiram
     */
    
    /* 从文件中读取二维数组 */
    func readMaze(filename string) [][]int {
    	file, err := os.Open(filename)
    	if err != nil {
    		panic(err)
    	}
    
    	var row, col int
    	fmt.Fscanf(file, "%d %d", &row, &col)
    
    	maze := make([][]int, row)
    	for i := range maze {
    		maze[i] = make([]int, col)
    		for j := range maze[i] {
    			fmt.Fscanf(file, "%d", &maze[i][j])
    		}
    	}
    
    	return maze
    }
    
    /* 记录位置 */
    type point struct {
    	i, j int
    }
    
    /* 上 左 下 右 */
    var dirs = [4]point{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}
    
    /* 通过相加移动位置*/
    func (p point) add(r point) point {
    	return point{p.i + r.i, p.j + r.j}
    }
    
    /* 判断这个点是否在二维数组中,如果在返回该节点 */
    func (p point) at(grid [][]int) (int, bool) {
    	if p.i < 0 || p.i >= len(grid) { //查看左右是否越界
    		return 0, false
    	}
    
    	if p.j < 0 || p.j >= len(grid[p.i]) { //查看上下是否越界
    		return 0, false
    	}
    
    	return grid[p.i][p.j], true
    }
    
    /* 产生广度优先遍历的的结果,记录在二维数组中 */
    func walk(maze [][]int, start, end point) [][]int {
    	steps := make([][]int, len(maze))
    	for i := range steps {
    		steps[i] = make([]int, len(maze[i]))
    	}
    
    	Q := []point{start}
    
    	for len(Q) > 0 {
    		cur := Q[0]
    		Q = Q[1:]
    
    		if cur == end {
    			break
    		}
    
    		for _, dir := range dirs {
    			next := cur.add(dir)
    
    			val, ok := next.at(maze)
    			if !ok || val == 1 { //不存在或者撞墙
    				continue
    			}
    
    			val, ok = next.at(steps)
    			if !ok || val != 0 { //不存在或者已经记录
    				continue
    			}
    
    			if next == start { //等于起始点
    				continue
    			}
    
    			curSteps, _ := cur.at(steps)         //获取步数
    			steps[next.i][next.j] = curSteps + 1 //记录步数在二维数组中
    
    			Q = append(Q, next) //将该节点添加进队尾
    		}
    	}
    
    	return steps
    }
    
    func main() {
    	maze := readMaze("src/maze/maze.in")
    
    	if len(maze) < 1 || len(maze[0]) < 1 {
    		fmt.Println("输入错误")
    		return
    	}
    	printTwoDimensionalArray(maze)
    	fmt.Println()
    	
    	steps := walk(maze, point{0, 0}, point{len(maze) - 1, len(maze[0]) - 1})
    
    	printTwoDimensionalArray(steps)
    
    	if len(steps) < 1 || len(steps[0]) < 1 || steps[len(steps)-1][len(steps[len(maze)-1])-1] == 0 {
    		fmt.Println("不能抵达终点")
    		return
    	}
    
    	stepPointArr := getStepPointArray(steps)
    
    	fmt.Println()
    	fmt.Println(stepPointArr)
    }
    
    /* 从结果集里面获取走出迷宫的最短路径 */
    func getStepPointArray(iss [][]int) []point {
    	var stepPointArr []point
    	var p point
    
    	var i, j = len(iss)-1, len(iss[len(iss)-1])-1
    	p = point{i, j}
    	var flag = true
    	for flag {
    		flag = false
    		stepPointArr = append(stepPointArr, p)
    		value, ok := p.at(iss)
    		if !ok || value == 0 {
    			break
    		}
    		for _, dir := range dirs {
    			next := p.add(dir)
    			val, isExist := next.at(iss)
    			if isExist && val >= 0 && val == value-1 {
    				p = next
    				flag = true
    				break
    			}
    		}
    	}
    
    	return stepPointArr
    }
    
    /* 打印二维数组*/
    func printTwoDimensionalArray(iss [][]int) {
    	for _, row := range iss {
    		for _, val := range row {
    			fmt.Printf("%3d", val)
    		}
    		fmt.Println()
    	}
    }
    
    

    运行结果

  • 相关阅读:
    Socket和ServerSocket学习笔记
    跨域资源共享的10种方式
    javascript执行环境(执行期上下文)详解
    js 自动插入分号
    原型对象prototype和原型属性[[Prototype]]
    构造自己的动画函数:animation,stop功能的实现
    sizzle源码分析 (4)sizzle 技术总结及值得我们学习的地方
    sizzle源码分析 (3)sizzle 不能快速匹配时 选择器流程
    sizzle源码分析 (2)ID 类 tag querySelectorAll 快速匹配
    sizzle源码分析 (1)sizzle架构
  • 原文地址:https://www.cnblogs.com/hirampeng/p/11229411.html
Copyright © 2011-2022 走看看