go语言实现迷宫的广度优先遍历

  迷宫的求解是非常常见的问题了,今天这里记录使用go语言来完成广度优先遍历

  要求时从文件中读出一个数字矩阵,0表示可以通行,1表示不可以。要求给出一条路径从左上角到右下角,使得路径的长度最短,可以使用6来标识路径,比如:

在这里插入图片描述
在这里插入图片描述

  这里需要说明的是,既然是找到最短路径,必须使用广度优先搜索来进行实现,广度优先搜索或许没有深度优先搜索快,但是找到的路径肯定是最短的,在上面的例子中其实已经展示的比较明显, 其实是有两条路可以走的,但是程序走了短的一条,关于具体的实现思路,在我的java实现中已经讲得非常详细了

  栈和队列(深度广度实现迷宫算法)

  在这里呢,其实也是使用额外的一个切片来记录中间过程,当有可以走的通路时,就在前一个通路的基础上加1,全程使用队列来进行广度遍历,中间表如下:
在这里插入图片描述
代码如下:

读取文件中的矩阵:
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)
		fmt.Fscanf(file,"%d")
		for j := range maze[i] {
			fmt.Fscanf(file,"%d",&maze[i][j])
		}
	}
	return maze
}
走迷宫的方法
func run(maze [][]int, start point, end point) [][]int{
	//生成steps矩阵
	steps := make([][]int, len(maze))
	for i := range steps {
		steps[i] = make([]int,len(maze[i]))
	}

	//生成队列,并把第一个节点放入队列
	Q := []point{{0,0}}

	//如果队列不为空,说明没有结束
	for len(Q) > 0 {
		//取出队头元素,并删除
		peek := Q[0]
		Q = Q[1:]

		//把该元素的上下左右都要走一步,看看是否走得通
		for _,dir := range dirs {
			next := peek.add(dir)
			if next.isNotAccess(steps,maze,start) {
				continue
			}
			//给steps赋值
			steps[next.i][next.j] = steps[peek.i][peek.j] + 1
			//放入队列
			Q = append(Q,next)
		}
	}
	return steps
}
定义坐标,上下左右,以及判断是否可以走
//定义坐标结构体
type point struct {
	i,j int
}

//定义当前元素的上下左右元素的差值
var dirs = [4]point {{-1,0},{1,0},{0,-1},{0,1}}

//定义next走差值的动作
func(p point) add(dir point) point{
	return point{p.i+dir.i,p.j+dir.j}
}

//判断next走不通的情况:1.遇到障碍,出边界  2.已经走过了,不能走回去  3.不能转个圈走回去了
func(next point) isNotAccess(steps [][]int,maze [][]int,start point) bool{
	if next.i < 0 || next.i >= len(maze) {
		return true
	}
	if next.j < 0 || next.j >= len(maze[0]) {
		return true
	}
	if maze[next.i][next.j] == 1 {
		return true
	}
	if steps[next.i][next.j] != 0 {
		return true
	}
	if next.i == start.i && next.j == start.j {
		return true
	}
	return false
}
打印迷宫路径
//从右下角往上面找,如果是少1,则为路径节点,
func changeMaze(maze [][]int, steps [][]int) [][]int{
	var cur = point{len(maze)-1,len(maze[0])-1}
	var start = point{0,0}
	for cur != start{
		//找四周节点,是否为当前节点的值-1
		for _, dir := range dirs {
			next := cur.add(dir)
			//判断是否合法
			if next.i >= 0 && next.i < len(maze) && next.j >= 0 && next.j < len(maze[0]) &&
				steps[next.i][next.j] == steps[cur.i][cur.j]-1 {
				//修改maze为6
				maze[cur.i][cur.j] = 6
				cur = next
			}
		}
	}
	maze[0][0] = 6
	return maze
}

  打印迷宫路径就是根据中间表,倒着找,这种结构类似于树,虽然从前往后可能出现多个分支,但是从后往前只有一个

main方法
func main() {
	//读出maze矩阵
	maze := readMaze2("maze/maze.in")
	//打印maze
	fmt.Println("maze:")
	for i := range maze {
		for j := range maze[0] {
			fmt.Printf("%4d",maze[i][j])
		}
		fmt.Println()
	}
	//开始走迷宫run. 从哪点到哪点
	steps := run(maze, point{0, 0}, point{len(maze) - 1, len(maze[0]) - 1})

	//根据steps来给出一条通路
	maze = changeMaze(maze, steps)

	fmt.Println("steps:")
	for i := range steps {
		for j := range steps[i] {
			fmt.Printf("%4d",steps[i][j])
		}
		fmt.Println()
	}

	fmt.Println("changed maze:")
	for i := range maze {
		for j := range maze[i] {
			fmt.Printf("%4d",maze[i][j])
		}
		fmt.Println()
	}
}

最后的结果:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 广度优先遍历可以用来寻找迷宫中的路径。下面是一个示例代码: ```python from queue import Queue def bfs(maze, start, end): queue = Queue() visited = set() queue.put(start) visited.add(start) path = {} path[start] = None while not queue.empty(): current = queue.get() if current == end: break for neighbor in get_neighbors(maze, current): if neighbor not in visited: queue.put(neighbor) visited.add(neighbor) path[neighbor] = current return get_path(path, start, end) def get_neighbors(maze, cell): neighbors = [] rows, cols = len(maze), len(maze[0]) row, col = cell if row > 0 and maze[row-1][col] == 0: neighbors.append((row-1, col)) if row < rows-1 and maze[row+1][col] == 0: neighbors.append((row+1, col)) if col > 0 and maze[row][col-1] == 0: neighbors.append((row, col-1)) if col < cols-1 and maze[row][col+1] == 0: neighbors.append((row, col+1)) return neighbors def get_path(path, start, end): current = end result = [] while current != start: result.append(current) current = path[current] result.append(start) result.reverse() return result ``` 其中,`maze` 是一个二维数组,表示迷宫,其中 0 表示可通过的格子,1 表示障碍物。`start` 和 `end` 分别表示起点和终点。 函数首先创建一个队列 `queue` 和一个集合 `visited`,将起点加入队列和集合中。然后创建一个字典 `path`,用于记录每个格子的前驱格子。接着进入循环,直到队列为空或者找到终点为止。每次从队列中取出一个格子 `current`,并遍历它的相邻格子,如果相邻格子是可通过的且没有被访问过,则将其加入队列和集合中,并在 `path` 中记录它的前驱格子为 `current`。 最后,调用 `get_path` 函数获取从起点到终点的路径。`get_path` 函数从终点开始,沿着 `path` 中记录的前驱格子一路向前,直到到达起点为止。 ### 回答2: 广度优先遍历是一种图的遍历算法,用于寻找迷宫中的路径。在迷宫中,我们可以将每个格子看作一个节点,相邻的格子之间存在着边。迷宫中通畅的路径就是从起始节点到目标节点的一条有效路径。 广度优先遍历算法的基本思想是从起始节点开始,依次访问其所有相邻的节点,并将这些节点依次加入一个队列中。然后再从队列头取出下一个节点进行访问,直到找到目标节点或者队列为空。 具体实现迷宫路径的广度优先遍历可以按照以下步骤进行: 1. 创建一个队列,将起始节点加入队列中。 2. 创建一个visited集合,用于记录已经访问过的节点。 3. 创建一个prev字典,用于记录每个节点的前驱节点,即每个节点是从哪个节点遍历而来。 4. 对于队列不为空的情况,重复以下步骤: - 从队列头取出一个节点作为当前节点。 - 如果当前节点是目标节点,则停止遍历,此时可以通过prev字典生成迷宫的路径。 - 否则,将当前节点标记为已访问,并遍历其所有相邻的节点: - 如果相邻节点没有被访问过,则将其加入队列,并将当前节点设置为其前驱节点。 5. 如果队列为空,但仍未找到目标节点,则说明迷宫中不存在可到达目标节点的路径。 通过广度优先遍历,我们可以找到从起始节点到目标节点的最短路径,因为遍历过程中,第一次访问到目标节点时,一定是经过的路径最短的。使用prev字典即可回溯出路径。 ### 回答3: 广度优先遍历是一种图的搜索算法,可以用于解决迷宫路径的问题。迷宫可以看作是一个由行和列组成的二维矩阵,其中的每个元素可以是墙壁、通路或终点。 广度优先遍历利用队列实现,从起点开始,将起点入队,并将其标记为已访问。然后,不断从队列中取出元素,并检查其周围的相邻节点是否可访问。如果可访问,则将其入队,并标记为已访问。直到队列为空为止,即找到了终点或者无法找到路径。 具体实现时,可以使用一个二维数组来表示迷宫,其中的元素值表示该位置的状态(0表示墙壁,1表示通路,2表示终点)。另外,可以使用一个二维数组来记录每个位置的步数,初始值为0。 首先,将起点入队,并将起点的步数设置为1。然后,进入循环,直到队列为空。在循环中,从队列中取出一个节点,再枚举其四个相邻节点(上、下、左、右)。对于每个相邻节点,如果该节点可访问且未被访问过,则将其入队,并将其步数设置为当前节点的步数加1。同时,标记该位置为已访问。如果某个相邻节点的值为2,则说明找到了终点,此时可退出循环。 最后,可以通过回溯的方式,从终点开始,沿着步数递减的路径依次找到起点,并将路径上的位置存入一个栈中。最后,将栈中的元素依次出栈,即可得到起点到终点的路径。 总结起来,广度优先遍历实现迷宫路径的步骤如下: 1. 将起点入队,并将其标记为已访问。 2. 进入循环,直到队列为空。 - 从队列中取出一个节点。 - 枚举其四个相邻节点。 - 如果相邻节点可访问且未被访问过,将其入队,并将其步数设置为当前节点的步数加1。同时,标记该位置为已访问。 - 如果某个相邻节点的值为2,退出循环。 3. 通过回溯的方式,找到起点到终点的路径,并存入一个栈中。 4. 将栈中的元素依次出栈,得到起点到终点的路径。 通过以上步骤,就可以使用广度优先遍历找到迷宫的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值