走迷宮問題廣度優先演算法實現
阿新 • • 發佈:2019-01-27
走迷宮問題
迷宮是許多小方格構成的矩形,在每個小方格中有的是牆(用1表示),有的是路(用0表示)。走迷宮就是從一個小方格沿上、下、左、右四個方向到鄰近的方格,當然不能穿牆。
問題描述
實現生成迷宮(從文字中讀取資料生成),輸出迷宮(圖案方式),探索迷宮路徑(最短路徑),輸出迷宮路徑(圖案方式)。
輸入的檔案內容格式為:
6 5
0 1 0 1 1
0 0 1 1 1
1 0 0 1 1
0 1 0 0 1
1 1 1 0 0
1 1 1 1 0
開頭一行表示地圖為6行5列,地圖中0表示路,1表示障礙物。現在規定從左上角進入迷宮從右下角出迷宮。
演算法分析
在任意位置,理論上有四個位置可以走,上下左右。現在位於位置0,走一步可以走的位置為:
也就是當前位置為0,可以走的位置為1,相同道理,走2步可以走的位置為:
當位於0時,可以探索的位置為周圍的四個1,廣度優先的演算法是根據狀態可分為兩種狀態,當前位置和下一步可以為的位置,當前位置為0,下一步可以為的位置為1,通過佇列將下一步位置先儲存起來,遍歷下一步可以為的4個1位置,再分別根據位於4個1位置時探索下一步的位置。如果當位於0位置找到一個下一步位置1之後再直接進行下一步探索則成了深度優先演算法。
以起始點為出發,將這個點按照某個方向規則走,周圍所有可以走的位置依次寫入到佇列,這個點走完之後,隊首出佇列,走這個點四周所有可以走的點,按照之前的規則,將周圍可走的點依次放入到佇列中,重複之前過程,直到佇列為空或者走到終點。在這個過程中在藉助一個輔助矩陣,存放起點到位置的最短路徑。
原始碼分析
//座標結構
type point struct {
i int
j int
}
//分別代表上左下右
var dirs = [4]point{
{-1, 0},
{ 0, -1},
{ 1, 0},
{ 0, 1},
}
//讀取地圖檔案
func readMaze(fileName string) [][]int {
file, err := os.Open(fileName)
if err != nil {
panic("open file fail")
}
var row, col int
var changeLine int
fmt.Fscanf(file, "%d %d", &row, &col)
maze := make([][]int, row)
for i := range maze {
maze[i] = make([]int, col)
//讀取檔案過程中遇到換行讀取為0
fmt.Fscanf(file, "%d", &changeLine)
for j := range maze[i] {
fmt.Fscanf(file, "%d", &maze[i][j])
}
}
return maze
}
func walkMaze(maze [][]int, start, end point)([][]int,bool) {
steps := make([][]int, len(maze))
for i := range steps {
steps[i] = make([]int, len(maze[0]))
}
//儲存四周下一步可以出現位置
Q := []point{start}
for len(Q) > 0 {
cur := Q[0]
Q = Q[1:]
for _, dir := range dirs {
next := cur.add(dir)
//1代表障礙物
nextValue, ok := next.at(maze)
if !ok || nextValue == 1 {
continue
}
//下一步必須是還沒走過的位置
nextValue, ok = next.at(steps)
if !ok || nextValue != 0 {
continue
}
//不能走到其實位置
if next == start {
continue
}
Q = append(Q,next)
mazeValue, ok := cur.at(steps)
if ok {
steps[next.i][next.j] = mazeValue + 1
}
}
}
//當走到終點時,則終點位置會被賦值為走過的步數
if steps[len(steps)-1][len(steps[0])-1] == 0 {
return steps,false
}
return steps,true
}